diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..71adc916 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "docker/database"] + path = docker/database + url = https://github.com/Banno/docker-postgresql-8.4/ + branch = postgres-8.4 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..b1dcd914 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +FROM tozd/runit:ubuntu-xenial + +EXPOSE 80/tcp +ENV DJANGO_SETTINGS_MODULE mainpage.settings +#Set secrets by uncommenting lines below +#ENV DB_PASSWORD ... +#Make this unique, and don't share it with anybody. +#ENV SECRET_KEY ... +#You can find them at: https://www.google.com/recaptcha/admin +#ENV RECAPTCHA_PUBLIC_KEY ... +#ENV RECAPTCHA_PRIVATE_KEY ... +#ENV PAYPAL_IDENTITY_TOKEN_PRODUCTION ... + +# Update packages +RUN apt-get update -q -q && \ + apt-get install --no-install-recommends -y git curl python python-dev python-pip python-setuptools build-essential libgeoip-dev libpq-dev swig libxml2-dev libxslt1-dev subversion mercurial libaprutil1 apache2-dev python2.7-dev nginx +RUN pip install --upgrade pip setuptools wheel six requests + +RUN ln -sf /dev/stdout /var/log/nginx/access.log +RUN ln -sf /dev/stdout /var/log/nginx/error.log + +ADD ./requirements.txt /code/requirements.txt +ADD ./requirements-production.txt /code/requirements-production.txt + +# Install Python package dependencies +RUN pip install -r /code/requirements-production.txt + +# Remove unneeded build-time dependencies +RUN apt-get purge python-dev build-essential -y && \ + apt-get autoremove -y && \ +rm -f /code/packages.txt /code/requirements.txt +COPY ./etc /etc +# Add the current version of the code (needed for production deployments) +WORKDIR /code +ADD . /code \ No newline at end of file diff --git a/README.rst b/README.rst index 805fc0e4..00bd1c20 100644 --- a/README.rst +++ b/README.rst @@ -1,37 +1,46 @@ -*wlan slovenija* main webpage -============================= +Mainpage +======== -Development installation ------------------------- +This is a repository for wlan-si web-page docker, it contains: -1. Clone from GitHub_ both webpage and nodewatcher_ repositories:: +- Web container for: django, uwgsi, nginx +- Database container with postgresql - git clone https://github.com/wlanslovenija/mainpage.git - git clone https://github.com/wlanslovenija/nodewatcher.git +Installation +------------ - You can also use SSH-based URLs or URLs of your forks. +Mainpage requires `docker `__ and +`docker-compose `__ to run. -2. Create and activate new `Python virtual environment`_:: +Download the repository to disk and run docker-compose build. - virtualenv --no-site-packages --distribute ~/.virtualenv/mainpage - source ~/.virtualenv/mainpage/bin/activate - -3. Move to location where you cloned webpage repository and run ``devsetup`` - script:: +.. code:: sh - python scripts/devsetup.py - - This script will install all requirements and import database dump to local database. + git clone https://github.com/wlanslovenija/mainpage + cd mainpage + docker-compose build -4. Run:: +Then just run the docker-compose up, which will set up the database +create media and static folders, merge the database, and bring up the +production server for mainpage. - python manage.py runserver +.. code:: sh - and start developing! + docker-compose up -You can safely rerun the ``devsetup`` as needed, but be advised that local -database content **will NOT be preserved**. +About +----- -.. _GitHub: https://github.com/ -.. _nodewatcher: http://dev.wlan-si.net/wiki/Nodewatcher -.. _Python virtual environment: http://www.virtualenv.org +This repository was a big part of my 2017 Gsoc project, it was suppose +to revive the unmaintained repository of wlan-si.net web-page, which had +a lot of broken dependencies, outdated dependencies and was not yet +running inside of a docker container. + +I managed to successfully create docker containers for both website and +database but my lack of django knowledge left me short of actually +fixing the django project that was suppose to run. + +Future +------ + +All that is left is for someone to fix the broken django project. \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..8d8196e8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3' +services: + web: + build: . + command: "service nginx start; scripts/docker-wait-pgsql; python scripts/migrate.py; uwsgi --socket /var/tmp/nodewatcher.sock --wsgi-file /code/mainpage/wsgi.py --uid www-data --gid www-data" + entrypoint: scripts/docker-run + environment: + PYTHONUNBUFFERED: 1 + volumes: + - .:/code + ports: + - "80:80" + db: + build: + context: docker/database/ + dockerfile: Dockerfile + environment: + POSTGRESQL_USER: wlansi_cms + POSTGRESQL_PASS: mainpage + POSTGRESQL_DB: wlansi + expose: + - 5432 \ No newline at end of file diff --git a/docker/database/Dockerfile b/docker/database/Dockerfile new file mode 100644 index 00000000..03486b6d --- /dev/null +++ b/docker/database/Dockerfile @@ -0,0 +1,25 @@ +FROM ubuntu:14.04 + +RUN apt-get update && apt-get install -y wget + +ADD pgdg.list /etc/apt/sources.list.d/pgdg.list +RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - + +RUN apt-get -qq update && LC_ALL=en_US.UTF-8 DEBIAN_FRONTEND=noninteractive apt-get install -y -q postgresql-8.4 libpq-dev + +# /etc/ssl/private can't be accessed from within container for some reason +# (@andrewgodwin says it's something AUFS related) +RUN mkdir /etc/ssl/private-copy; mv /etc/ssl/private/* /etc/ssl/private-copy/; rm -r /etc/ssl/private; mv /etc/ssl/private-copy /etc/ssl/private; chmod -R 0700 /etc/ssl/private; chown -R postgres /etc/ssl/private + +## Add over config files +ADD postgresql.conf /etc/postgresql/8.4/main/postgresql.conf +ADD pg_hba.conf /etc/postgresql/8.4/main/pg_hba.conf +RUN chown postgres:postgres /etc/postgresql/8.4/main/*.conf +ADD init-postgresql /usr/local/bin/init-postgresql +RUN chmod +x /usr/local/bin/init-postgresql + +VOLUME ["/var/lib/postgresql"] +EXPOSE 5432 + +CMD ["/usr/local/bin/init-postgresql"] + diff --git a/etc/nginx/sites-enabled/default b/etc/nginx/sites-enabled/default new file mode 100644 index 00000000..5657f0d3 --- /dev/null +++ b/etc/nginx/sites-enabled/default @@ -0,0 +1,25 @@ +upstream mainpage { + server unix:/var/tmp/nodewatcher.sock; +} +access_log /var/log/nginx/access.log; +error_log /var/log/nginx/error.log; +server { + listen 80 default_server; + server_name _; + charset utf-8; + root /tmp; + + location /static { + alias /code/mainpage/wlansi/static; + } + + location /media { + alias /code/mainpage/media/; + } + + location / { + uwsgi_pass mainpage; + include /etc/nginx/uwsgi_params; + } +} + diff --git a/etc/nginx/uwsgi_params b/etc/nginx/uwsgi_params new file mode 100644 index 00000000..f539451b --- /dev/null +++ b/etc/nginx/uwsgi_params @@ -0,0 +1,16 @@ + +uwsgi_param QUERY_STRING $query_string; +uwsgi_param REQUEST_METHOD $request_method; +uwsgi_param CONTENT_TYPE $content_type; +uwsgi_param CONTENT_LENGTH $content_length; + +uwsgi_param REQUEST_URI $request_uri; +uwsgi_param PATH_INFO $document_uri; +uwsgi_param DOCUMENT_ROOT $document_root; +uwsgi_param SERVER_PROTOCOL $server_protocol; +uwsgi_param HTTPS $https if_not_empty; + +uwsgi_param REMOTE_ADDR $remote_addr; +uwsgi_param REMOTE_PORT $remote_port; +uwsgi_param SERVER_PORT $server_port; +uwsgi_param SERVER_NAME $server_name; diff --git a/etc/service/nginx/run b/etc/service/nginx/run new file mode 100755 index 00000000..2e401399 --- /dev/null +++ b/etc/service/nginx/run @@ -0,0 +1,4 @@ +#!/bin/bash -e + +exec /usr/sbin/nginx -g 'daemon off;' 2>&1 + diff --git a/etc/service/postgresql/run.initialization b/etc/service/postgresql/run.initialization new file mode 100644 index 00000000..088d9af2 --- /dev/null +++ b/etc/service/postgresql/run.initialization @@ -0,0 +1,2 @@ +apt -y install postgresql-9.6-ip4r +psql -c "create extension ip4r" wlansi \ No newline at end of file diff --git a/etc/service/uwsgi/log/run b/etc/service/uwsgi/log/run new file mode 100755 index 00000000..7ae04bc3 --- /dev/null +++ b/etc/service/uwsgi/log/run @@ -0,0 +1,7 @@ +#!/bin/bash -e + +mkdir -p /var/log/uwsgi +chown nobody:nogroup /var/log/uwsgi + +exec chpst -u nobody:nogroup svlogd -tt /var/log/uwsgi + diff --git a/etc/service/uwsgi/run b/etc/service/uwsgi/run new file mode 100755 index 00000000..e041c237 --- /dev/null +++ b/etc/service/uwsgi/run @@ -0,0 +1,13 @@ +#!/bin/bash -e + +mkdir -p /media +chown -R www-data:www-data /media + +mkdir -p /static +cd / + +python manage.py collectstatic --noinput +python manage.py migrate --noinput + +exec /usr/bin/uwsgi --plugin python --ini /etc/uwsgi/nodewatcher.ini 2>&1 + diff --git a/etc/uwsgi/mainpage.ini b/etc/uwsgi/mainpage.ini new file mode 100644 index 00000000..a65d545f --- /dev/null +++ b/etc/uwsgi/mainpage.ini @@ -0,0 +1,10 @@ +[uwsgi] +uid = www-data +gid = www-data +chdir = /code +module = mainpage.wsgi +master = true +processes = 10 +socket = /var/tmp/mainpage.sock +harakiri = 120 +max-requests = 1000 diff --git a/mainpage/frontend/__init__.py b/mainpage/frontend/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mainpage/frontend/account/__init__.py b/mainpage/frontend/account/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mainpage/frontend/account/geo_fields.py b/mainpage/frontend/account/geo_fields.py new file mode 100644 index 00000000..f75e21cc --- /dev/null +++ b/mainpage/frontend/account/geo_fields.py @@ -0,0 +1,366 @@ +# Based on http://code.djangoproject.com/ticket/5446 +# Should be changed to use upstream code once it has been merged into it. + +from django.conf import settings +from django.contrib.gis import utils as gis_utils +from django.db.models import fields +from django.utils import encoding as utils_encoding +from django.utils import translation +from django.utils.translation import ugettext_lazy as _ + +# Countries list - ISO 3166-1 +# http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 +# http://en.wikipedia.org/wiki/List_of_national_capitals + +COUNTRIES = ( + ('AD', _('Andorra'), _('Andorra la Vella')), + ('AE', _('United Arab Emirates'), _('Abu Dhabi')), + ('AF', _('Afghanistan'), _('Kabul')), + ('AG', _('Antigua and Barbuda'), _("St. John's")), + ('AI', _('Anguilla'), _('The Valley')), + ('AL', _('Albania'), _('Tirana')), + ('AM', _('Armenia'), _('Yerevan')), + ('AN', _('Netherlands Antilles'), _('Willemstad')), + ('AO', _('Angola'), _('Luanda')), + ('AQ', _('Antarctica'), ''), + ('AR', _('Argentina'), _('Buenos Aires')), + ('AS', _('American Samoa'), _('Pago Pago')), + ('AT', _('Austria'), _('Vienna')), + ('AU', _('Australia'), _('Canberra')), + ('AW', _('Aruba'), _('Oranjestad')), + ('AX', _('Aland Islands'), _('Mariehamn')), + ('AZ', _('Azerbaijan'), _('Baku')), + ('BA', _('Bosnia and Herzegovina'), _('Sarajevo')), + ('BB', _('Barbados'), _('Bridgetown')), + ('BD', _('Bangladesh'), _('Dhaka')), + ('BE', _('Belgium'), _('Brussels')), + ('BF', _('Burkina Faso'), _('Ouagadougou')), + ('BG', _('Bulgaria'), _('Sofia')), + ('BH', _('Bahrain'), _('Manama')), + ('BI', _('Burundi'), _('Bujumbura')), + ('BJ', _('Benin'), _('Porto-Novo')), + ('BL', _('Saint Barthelemy'), _('Gustavia')), + ('BM', _('Bermuda'), _('Hamilton')), + ('BN', _('Brunei'), _('Bandar Seri Begawan')), + ('BO', _('Bolivia'), _('Sucre')), + ('BR', _('Brazil'), _('Brasilia')), + ('BS', _('Bahamas'), _('Nassau')), + ('BT', _('Bhutan'), _('Thimphu')), + ('BV', _('Bouvet Island'), ''), + ('BW', _('Botswana'), _('Gaborone')), + ('BY', _('Belarus'), _('Minsk')), + ('BZ', _('Belize'), _('Belmopan')), + ('CA', _('Canada'), _('Ottawa')), + ('CC', _('Cocos (Keeling) Islands'), _('West Island')), + ('CD', _('Congo, the Democratic Republic of the'), _('Kinshasa')), + ('CF', _('Central African Republic'), _('Bangui')), + ('CG', _('Congo, the Republic of the'), _('Brazzaville')), + ('CH', _('Switzerland'), _('Bern')), + ('CI', _('Ivory Coast'), _('Yamoussoukro')), + ('CK', _('Cook Islands'), _('Avarua')), + ('CL', _('Chile'), _('Santiago')), + ('CM', _('Cameroon'), _('Yaounde')), + ('CN', _('China'), _('Beijing')), + ('CO', _('Colombia'), _('Bogota')), + ('CR', _('Costa Rica'), _('San Jose')), + ('CU', _('Cuba'), _('Havana')), + ('CV', _('Cape Verde'), _('Praia')), + ('CX', _('Christmas Island'), _('Flying Fish Cove')), + ('CY', _('Cyprus'), _('Nicosia')), + ('CZ', _('Czech Republic'), _('Prague')), + ('DE', _('Germany'), _('Berlin')), + ('DJ', _('Djibouti'), _('Djibouti')), + ('DK', _('Denmark'), _('Copenhagen')), + ('DM', _('Dominica'), _('Roseau')), + ('DO', _('Dominican Republic'), _('Santo Domingo')), + ('DZ', _('Algeria'), _('Algiers')), + ('EC', _('Ecuador'), _('Quito')), + ('EE', _('Estonia'), _('Tallinn')), + ('EG', _('Egypt'), _('Cairo')), + ('EH', _('Western Sahara'), _('El Aaiun')), + ('ER', _('Eritrea'), _('Asmara')), + ('ES', _('Spain'), _('Madrid')), + ('ET', _('Ethiopia'), _('Addis Ababa')), + ('FI', _('Finland'), _('Helsinki')), + ('FJ', _('Fiji'), _('Suva')), + ('FK', _('Falkland Islands'), _('Stanley')), + ('FM', _('Micronesia'), _('Palikir')), + ('FO', _('Faroe Islands'), _('Torshavn')), + ('FR', _('France'), _('Paris')), + ('GA', _('Gabon'), _('Libreville')), + ('GB', _('United Kingdom'), _('London')), + ('GD', _('Grenada'), _("St. George's")), + ('GE', _('Georgia'), _('Tbilisi')), + ('GF', _('French Guiana'), _('Cayenne')), + ('GG', _('Guernsey'), _('Saint Peter Port')), + ('GH', _('Ghana'), _('Accra')), + ('GI', _('Gibraltar'), _('Gibraltar')), + ('GL', _('Greenland'), _('Nuuk')), + ('GM', _('Gambia'), _('Banjul')), + ('GN', _('Guinea'), _('Conakry')), + ('GP', _('Guadeloupe'), _('Basse-Terre')), + ('GQ', _('Equatorial Guinea'), _('Malabo')), + ('GR', _('Greece'), _('Athens')), + ('GS', _('South Georgia and the South Sandwich Islands'), _('Grytviken')), + ('GT', _('Guatemala'), _('Guatemala City')), + ('GU', _('Guam'), _('Hagatna')), + ('GW', _('Guinea-Bissau'), _('Bissau')), + ('GY', _('Guyana'), _('Georgetown')), + ('HK', _('Hong Kong'), _('Hong Kong')), + ('HM', _('Heard Island and McDonald Islands'), ''), + ('HN', _('Honduras'), _('Tegucigalpa')), + ('HR', _('Croatia'), _('Zagreb')), + ('HT', _('Haiti'), _('Port-au-Prince')), + ('HU', _('Hungary'), _('Budapest')), + ('ID', _('Indonesia'), _('Jakarta')), + ('IE', _('Ireland'), _('Dublin')), + ('IL', _('Israel'), _('Jerusalem')), + ('IM', _('Isle of Man'), _('Douglas')), + ('IN', _('India'), _('New Delhi')), + ('IO', _('British Indian Ocean Territory'), _('Diego Garcia')), + ('IQ', _('Iraq'), _('Iraq')), + ('IR', _('Iran'), _('Tehran')), + ('IS', _('Iceland'), _('Reykjavik')), + ('IT', _('Italy'), _('Rome')), + ('JE', _('Jersey'), _('Saint Helier')), + ('JM', _('Jamaica'), _('Kingston')), + ('JO', _('Jordan'), _('Amman')), + ('JP', _('Japan'), _('Tokyo')), + ('KE', _('Kenya'), _('Nairobi')), + ('KG', _('Kyrgyzstan'), _('Bishkek')), + ('KH', _('Cambodia'), _('Phnom Penh')), + ('KI', _('Kiribati'), _('South Tarawa')), + ('KM', _('Comoros'), _('Moroni')), + ('KN', _('Saint Kitts and Nevis'), _('Basseterre')), + ('KP', _('North Korea'), _('Pyongyang')), + ('KR', _('South Korea'), _('Seoul')), + ('KW', _('Kuwait'), _('Kuwait City')), + ('KY', _('Cayman Islands'), _('George Town')), + ('KZ', _('Kazakhstan'), _('Astana')), + ('LA', _('Laos'), _('Vientiane')), + ('LB', _('Lebanon'), _('Beirut')), + ('LC', _('Saint Lucia'), _('Castries')), + ('LI', _('Liechtenstein'), _('Vaduz')), + ('LK', _('Sri Lanka'), _('Sri Jayawardenepura Kotte')), + ('LR', _('Liberia'), _('Monrovia')), + ('LS', _('Lesotho'), _('Maseru')), + ('LT', _('Lithuania'), _('Vilnius')), + ('LU', _('Luxembourg'), _('Luxembourg City')), + ('LV', _('Latvia'), _('Riga')), + ('LY', _('Libya'), _('Tripoli')), + ('MA', _('Morocco'), _('Rabat')), + ('MC', _('Monaco'), _('Monaco')), + ('MD', _('Moldova'), _('Chisinau')), + ('ME', _('Montenegro'), _('Podgorica')), + ('MG', _('Madagascar'), _('Antananarivo')), + ('MH', _('Marshall Islands'), _('Majuro')), + ('MK', _('Macedonia'), _('Skopje')), + ('ML', _('Mali'), _('Bamako')), + ('MM', _('Myanmar'), _('Naypyidaw')), + ('MN', _('Mongolia'), _('Ulaanbaatar')), + ('MO', _('Macao'), _('Macao')), + ('MP', _('Northern Mariana Islands'), _('Saipan')), + ('MQ', _('Martinique'), _('Fort-de-France')), + ('MR', _('Mauritania'), _('Nouakchott')), + ('MS', _('Montserrat'), _('Brades')), + ('MT', _('Malta'), _('Valletta')), + ('MU', _('Mauritius'), _('Port Louis')), + ('MV', _('Maldives'), _('Male')), + ('MW', _('Malawi'), _('Lilongwe')), + ('MX', _('Mexico'), _('Mexico City')), + ('MY', _('Malaysia'), _('Putrajaya')), + ('MZ', _('Mozambique'), _('Maputo')), + ('NA', _('Namibia'), _('Windhoek')), + ('NC', _('New Caledonia'), _('Noumea')), + ('NE', _('Niger'), _('Niamey')), + ('NF', _('Norfolk Island'), _('Kingston')), + ('NG', _('Nigeria'), _('Abuja')), + ('NI', _('Nicaragua'), _('Managua')), + ('NL', _('Netherlands'), _('Amsterdam')), + ('NO', _('Norway'), _('Oslo')), + ('NP', _('Nepal'), _('Kathmandu')), + ('NR', _('Nauru'), _('Yaren')), + ('NU', _('Niue'), _('Alofi')), + ('NZ', _('New Zealand'), _('Wellington')), + ('OM', _('Oman'), _('Muscat')), + ('PA', _('Panama'), _('Panama City')), + ('PE', _('Peru'), _('Lima')), + ('PF', _('French Polynesia'), _('Papeete')), + ('PG', _('Papua New Guinea'), _('Port Moresby')), + ('PH', _('Philippines'), _('Manila')), + ('PK', _('Pakistan'), _('Islamabad')), + ('PL', _('Poland'), _('Warsaw')), + ('PM', _('Saint Pierre and Miquelon'), _('St. Pierre')), + ('PN', _('Pitcairn Islands'), _('Adamstown')), + ('PR', _('Puerto Rico'), _('San Juan')), + ('PS', _('Palestine'), _('Jerusalem')), + ('PT', _('Portugal'), _('Lisbon')), + ('PW', _('Palau'), _('Ngerulmud')), + ('PY', _('Paraguay'), _('Asuncion')), + ('QA', _('Qatar'), _('Doha')), + ('RE', _('Reunion'), _('Saint-Denis')), + ('RO', _('Romania'), _('Bucharest')), + ('RS', _('Serbia'), _('Belgrade')), + ('RU', _('Russia'), _('Moscow')), + ('RW', _('Rwanda'), _('Kigali')), + ('SA', _('Saudi Arabia'), _('Riyadh')), + ('SB', _('Solomon Islands'), _('Honiara')), + ('SC', _('Seychelles'), _('Victoria')), + ('SD', _('Sudan'), _('Khartoum')), + ('SE', _('Sweden'), _('Stockholm')), + ('SG', _('Singapore'), _('Singapore')), + ('SH', _('Saint Helena'), _('Jamestown')), + ('SI', _('Slovenia'), _('Ljubljana')), + ('SJ', _('Svalbard and Jan Mayen'), _('Longyearbyen')), + ('SK', _('Slovakia'), _('Bratislava')), + ('SL', _('Sierra Leone'), _('Freetown')), + ('SM', _('San Marino'), _('San Marino')), + ('SN', _('Senegal'), _('Dakar')), + ('SO', _('Somalia'), _('Mogadishu')), + ('SR', _('Suriname'), _('Paramaribo')), + ('ST', _('Sao Tome and Principe'), _('Sao Tome')), + ('SV', _('El Salvador'), _('San Salvador')), + ('SY', _('Syria'), _('Damascus')), + ('SZ', _('Swaziland'), _('Mbabane')), + ('TC', _('Turks and Caicos Islands'), _('Cockburn Town')), + ('TD', _('Chad'), _("N'Djamena")), + ('TF', _('French Southern Territories'), _('Port-aux-Francais')), + ('TG', _('Togo'), _('Lome')), + ('TH', _('Thailand'), _('Bangkok')), + ('TJ', _('Tajikistan'), _('Dushanbe')), + ('TK', _('Tokelau'), _('Nukunonu')), + ('TL', _('Timor-Leste'), _('Dili')), + ('TM', _('Turkmenistan'), _('Ashgabat')), + ('TN', _('Tunisia'), _('Tunis')), + ('TO', _('Tonga'), _("Nuku'alofa")), + ('TR', _('Turkey'), _('Ankara')), + ('TT', _('Trinidad and Tobago'), _('Port of Spain')), + ('TV', _('Tuvalu'), _('Funafuti')), + ('TW', _('Taiwan'), _('Taipei')), + ('TZ', _('Tanzania'), _('Dodoma')), + ('UA', _('Ukraine'), _('Kiev')), + ('UG', _('Uganda'), _('Kampala')), + ('UM', _('United States Minor Outlying Islands'), _('Wake Island')), + ('US', _('United States'), _('Washington, D.C.')), + ('UY', _('Uruguay'), _('Montevideo')), + ('UZ', _('Uzbekistan'), _('Tashkent')), + ('VA', _('Vatican City'), _('Vatican City')), + ('VC', _('Saint Vincent and the Grenadines'), _('Kingstown')), + ('VE', _('Venezuela'), _('Caracas')), + ('VG', _('Virgin Islands, British'), _('Road Town')), + ('VI', _('Virgin Islands, United States'), _('Charlotte Amalie')), + ('VN', _('Vietnam'), _('Hanoi')), + ('VU', _('Vanuatu'), _('Port Vila')), + ('WF', _('Wallis and Futuna'), _('Mata-Utu')), + ('WS', _('Samoa'), _('Apia')), + ('YE', _('Yemen'), _('Sanaa')), + ('YT', _('Mayotte'), _('Mamoudzou')), + ('ZA', _('South Africa'), _('Pretoria')), + ('ZM', _('Zambia'), _('Lusaka')), + ('ZW', _('Zimbabwe'), _('Harare')), + ('ZZ', _('Unknown or unspecified country'), ''), +) + + +def sorted_countries(countries): + """ + Sort countries for a given language. + + Assume ZZ is the last entry, keep it last. + """ + + c = [c[0:2] for c in countries[:-1]] + c.sort(key=lambda x: x[1]) + c.append(countries[-1][0:2]) + return tuple(c) + + +countries_choices = sorted_countries(COUNTRIES) +languages_choices = map(lambda (code, name): (code, _(name)), settings.LANGUAGES) # We have to translate names +countries_cities = dict([(c[0], c[2]) for c in COUNTRIES[:-1]]) + +CITIES = sorted(countries_cities.values()) + +if gis_utils.HAS_GEOIP: + geoip_resolver = gis_utils.GeoIP() +else: + geoip_resolver = None + import logging + + logging.warning("GeoIP library not available.") + + +def get_initial_country(request=None): + """ + Returns a contry code based on a client's remote address or settings. + """ + + if request: + country = geoip_resolver and geoip_resolver.country_code(request.META['REMOTE_ADDR']) + if country and country.upper() in countries_cities: + return country.upper() + return settings.DEFAULT_COUNTRY + + +def get_initial_city(request=None): + """ + Returns a city name based on a client's remote address or a default city from her country. + """ + + # We force unicode here so that default value in a field is a proper unicode string and not a lazy one + # Otherwise psycopg2 raises an "can't adapt" error: http://code.djangoproject.com/ticket/13965 + + if request: + city = geoip_resolver and geoip_resolver.city(request.META['REMOTE_ADDR']) + if city and city.get('city'): + return city['city'] + return utils_encoding.force_unicode(countries_cities[get_initial_country(request)]) or getattr(settings, + 'DEFUALT_CITY', + None) + return getattr(settings, 'DEFUALT_CITY', None) or utils_encoding.force_unicode( + countries_cities[get_initial_country()]) + + +def get_initial_language(request=None): + """ + Returns language code based on a request or settings. + """ + + if request: + return translation.get_language_from_request(request) + return settings.LANGUAGE_CODE + + +class CountryField(fields.CharField): + def __init__(self, *args, **kwargs): + kwargs.setdefault('max_length', 2) + kwargs.setdefault('choices', countries_choices) + kwargs.setdefault('default', get_initial_country) + + super(fields.CharField, self).__init__(*args, **kwargs) + + def get_internal_type(self): + return "CharField" + + +class CityField(fields.CharField): + def __init__(self, *args, **kwargs): + kwargs.setdefault('max_length', 150) + kwargs.setdefault('default', get_initial_city) + + super(fields.CharField, self).__init__(*args, **kwargs) + + def get_internal_type(self): + return "CharField" + + +class LanguageField(fields.CharField): + def __init__(self, *args, **kwargs): + kwargs.setdefault('max_length', 5) + kwargs.setdefault('choices', languages_choices) + kwargs.setdefault('default', get_initial_language) + + super(fields.CharField, self).__init__(*args, **kwargs) + + def get_internal_type(self): + return "CharField" diff --git a/mainpage/settings.py b/mainpage/settings.py index 59f0c807..6e018998 100644 --- a/mainpage/settings.py +++ b/mainpage/settings.py @@ -5,10 +5,9 @@ settings_dir = os.path.abspath(os.path.dirname(__file__)) database_file = os.path.join(settings_dir, 'db.sqlite') -# Website requires nodewatcher, so for easier development we assume -# it is accessible in the same directory website repository is -nodewatcher_dir = os.path.abspath(os.path.join(settings_dir, '..', '..', 'nodewatcher', 'nodewatcher')) -sys.path.insert(0, nodewatcher_dir) + +sys.path.append("/code/mainpage/") + # Dummy function, so that "makemessages" can find strings which should be translated. _ = lambda s: s @@ -20,19 +19,20 @@ # DEBUG=False and a view raises an exception, Django will e-mail these # people with the full exception information. Each member of the tuple # should be a tuple of (Full name, e-mail address). -ADMINS = ( -) +ADMINS = () MANAGERS = ADMINS +DB_PASSWORD = os.environ.get('DB_PASSWORD', 'mainpage') + DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.sqlite3', # 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': database_file, # Or path to database file if using sqlite3. - 'USER': '', # Not used with sqlite3. - 'PASSWORD': '', # Not used with sqlite3. - 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. - 'PORT': '', # Set to empty string for default. Not used with sqlite3. + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'wlansi', + 'USER': 'wlansi_cms', + 'PASSWORD': DB_PASSWORD, + 'HOST': 'db', + 'PORT': '', }, } @@ -55,13 +55,12 @@ ) LOCALE_PATHS = ( - os.path.join(settings_dir, 'locale'), + "code/mainpage/locale", ) ADMIN_LANGUAGE_CODE = 'en' -import frontend -GEOIP_PATH = os.path.abspath(os.path.join(os.path.dirname(frontend.__file__), '..', 'geoip')) +GEOIP_PATH = 'libs/geoip/' DEFAULT_COUNTRY = 'SI' URL_VALIDATOR_USER_AGENT = 'Django' @@ -205,9 +204,6 @@ 'cmsplugin_markup_tracwiki', # Ours are first so that we can override default templates in other apps - 'frontend.account', - 'frontend.dns', - 'frontend.nodes', 'mainpage.wlansi', 'mainpage.wlansi.accounting', 'mainpage.wlansi.buynow', @@ -294,7 +290,7 @@ LOGOUT_URL = '/admin/' AUTHENTICATION_BACKENDS = ( - 'frontend.account.auth.ModelBackend', + 'django.contrib.auth.backends.ModelBackend', ) CACHES = { diff --git a/mainpage/settings_production.py b/mainpage/settings_production.py index fa925932..47e96434 100644 --- a/mainpage/settings_production.py +++ b/mainpage/settings_production.py @@ -4,9 +4,6 @@ from .settings import * -# Secrets are in a separate file so they are not visible in public repository -from .secrets import * - DEBUG = False TEMPLATE_DEBUG = DEBUG @@ -16,9 +13,8 @@ MANAGERS = ADMINS -# We set search path to include nodewatcher's schema, so we can share some -# tables (like users) between them. The idea is that we delete users table from -# mainpage's schema so that it is found in nodewatcher's schema. +#DB_PASSWORD is defined in Dockerfile +DB_PASSWORD = os.environ.get('DB_PASSWORD', 'mainpage') DATABASES = { 'default': { @@ -26,13 +22,13 @@ 'NAME': 'wlansi', 'USER': 'wlansi_cms', 'PASSWORD': DB_PASSWORD, - 'HOST': 'localhost', + 'HOST': 'db', 'PORT': '', - 'SCHEMA_SEARCH_PATH': ('wlansi_cms', 'wlansi_nw'), }, } -# SECRET_KEY is in secrets +# SECRET_KEY is defined in Dockerfile +SECRET_KEY = os.environ.get('SECRET_KEY', 'ilikejimmyjams') CSRF_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True @@ -52,8 +48,10 @@ }, } -# RECAPTCHA_PUBLIC_KEY is in secrets -# RECAPTCHA_PRIVATE_KEY is in secrets +# RECAPTCHA_PUBLIC_KEY is defined in Dockerfile +RECAPTCHA_PUBLIC_KEY = os.environ.get('RECAPTCHA_PUBLIC_KEY') +# RECAPTCHA_PRIVATE_KEY is defined in Dockerfile +RECAPTCHA_PRIVATE_KEY = os.environ.get('RECAPTCHA_PRIVATE_KEY') CMS_MARKUP_TRAC_COMPONENTS += ( 'tracdashessyntax.plugin.DashesSyntaxPlugin', @@ -99,8 +97,8 @@ if not DEBUG: PAYPAL_TEST = DEBUG PAYPAL_DEBUG = PAYPAL_TEST - # PAYPAL_IDENTITY_TOKEN_PRODUCTION is in secrets - PAYPAL_IDENTITY_TOKEN = PAYPAL_IDENTITY_TOKEN_PRODUCTION + # PAYPAL_IDENTITY_TOKEN is defined in Dockerfile + PAYPAL_IDENTITY_TOKEN = os.environ.get('PAYPAL_IDENTITY_TOKEN_PRODUCTION') PAYPAL_RECEIVER_EMAIL = 'mitar@tnode.com' PAYPAL_RECEIVER_EMAIL_ALIAS = 'order@wlan-si.net' PAYPAL_RECEIVER_EMAIL_DONATION_ALIAS = 'donate@wlan-si.net' @@ -110,3 +108,5 @@ PAYPAL_CERT_ID = 'EWMRL6RHUA6NE' USE_HTTPS = True + +ALLOWED_HOSTS = ["*"] \ No newline at end of file diff --git a/mainpage/wlansi/context_processors.py b/mainpage/wlansi/context_processors.py index 04f64e44..53c3e974 100644 --- a/mainpage/wlansi/context_processors.py +++ b/mainpage/wlansi/context_processors.py @@ -8,13 +8,16 @@ def global_vars(request): """ supporters_images = {} - for supporter in foldermodels.Folder.objects.get(name=settings.SUPPORTERS_FILER_FOLDER_NAME).files.instance_of(imagemodels.Image).filter(is_public=True).order_by('name'): - if '-color' in supporter.label: - name = supporter.label.replace('-color', '') - supporters_images.setdefault(name, {})['color'] = supporter - elif '-gray' in supporter.label: - name = supporter.label.replace('-gray', '') - supporters_images.setdefault(name, {})['gray'] = supporter + try: + for supporter in foldermodels.Folder.objects.get(name=settings.SUPPORTERS_FILER_FOLDER_NAME).files.instance_of(imagemodels.Image).filter(is_public=True).order_by('name'): + if '-color' in supporter.label: + name = supporter.label.replace('-color', '') + supporters_images.setdefault(name, {})['color'] = supporter + elif '-gray' in supporter.label: + name = supporter.label.replace('-gray', '') + supporters_images.setdefault(name, {})['gray'] = supporter + except Exception, e: + print e supporters = [] for name, images in supporters_images.items(): diff --git a/mainpage/wlansi/inmedia/models.py b/mainpage/wlansi/inmedia/models.py index ed72f5b9..74ce99f6 100644 --- a/mainpage/wlansi/inmedia/models.py +++ b/mainpage/wlansi/inmedia/models.py @@ -6,6 +6,7 @@ from frontend.account import geo_fields + class InMediaEntry(models.Model): date = models.DateField() link = models.URLField(blank=True, help_text=_("URL of official publication, if available.")) @@ -39,6 +40,7 @@ def get_language(self): def __unicode__(self): return unicode(_(u"%(source)s on %(date)s" % {'source': self.source(), 'date': self.date})) + class InMediaLocalCopy(models.Model): entry = models.ForeignKey(InMediaEntry, related_name='local_copies') local_copy = file.FilerFileField(help_text=_("Because official publications often disappear, we try to make also local copies (PDFs, audio and video recordings, etc.).")) @@ -52,6 +54,7 @@ class Meta: def __unicode__(self): return unicode(self.local_copy) + class InMediaDescription(models.Model): entry = models.ForeignKey(InMediaEntry, related_name='descriptions') language = geo_fields.LanguageField() diff --git a/requirements-production-python26.txt b/requirements-production-python26.txt deleted file mode 100644 index a20a1713..00000000 --- a/requirements-production-python26.txt +++ /dev/null @@ -1,2 +0,0 @@ -importlib==1.0.2 --r requirements-production.txt diff --git a/requirements-production.txt b/requirements-production.txt index a2fe3226..e176e8e7 100644 --- a/requirements-production.txt +++ b/requirements-production.txt @@ -1,11 +1,6 @@ -GeoIP-Python==1.2.7 --e svn+http://trac-hacks.org/svn/footnotemacro/trunk@11926#egg=FootNoteMacro-dev_r11926 +-r /code/requirements.txt +GeoIP==1.3.2 GitPython==0.3.2.RC1 --e git+https://github.com/mitar/trac-mathjax.git@e5b2bcbd8ec74685407c6fb2e71fb56cc2f47484#egg=MathJaxPlugin-dev --e svn+http://trac-hacks.org/svn/dashessyntaxplugin/0.11@8543#egg=TracDashesSyntaxPlugin-dev_r8543 --e hg+https://bitbucket.org/kisielk/tracmathplugin@05cd705cc9eadf322d5b8395fad1ffb0a6efeab5#egg=TracMath-dev gitdb==0.5.4 -psycopg2==2.2.1 -python-aprmd5==0.2 -M2Crypto==0.21.1 --r requirements.txt +psycopg2==2.4.3 +M2Crypto==0.26.0 diff --git a/requirements.txt b/requirements.txt index 37a290a4..92c42a05 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ -Django==1.4 +Django==1.4.0 Genshi==0.6 Markdown==2.1.1 -PIL==1.1.7 +Pillow==4.2.1 PyYAML==3.10 Pygments==1.5 South==0.7.5 @@ -10,16 +10,11 @@ amqplib==1.0.2 anyjson==0.3.1 async==0.6.1 chardet==1.0.1 --e git+https://github.com/wlanslovenija/cmsplugin-blog.git@0829d67e47934ab021206661ad5df7e7e1573b89#egg=cmsplugin_blog-dev --e git+https://github.com/maccesch/cmsplugin-contact.git@ea95740655582faf603cb2f0f772f3600f952a6b#egg=cmsplugin_contact-dev --e git+https://github.com/stefanfoulis/cmsplugin-filer.git@9f2e5959c25b849ba64d4a6be10d6ccd7278e050#egg=cmsplugin_filer-dev cmsplugin-markup==0.2.2 cmsplugin-markup-tracwiki==0.2.2 -distribute==0.6.27 +distribute==0.7.3 django-appconf==0.5 django-classy-tags==0.3.4.1 --e git+https://github.com/mitar/django-cms.git@0bcf0409d5a052f136850cd03f6b54149a3983c5#egg=django_cms-dev --e git+https://github.com/mitar/django-filer.git@d9917b1458c5abd41f47bc98c56d197d4ccd6fa0#egg=django_filer-dev django-missing==0.1.11 django-mptt==0.5.2 django-paypal==0.1.2 @@ -46,7 +41,18 @@ python-dateutil==1.5 python-memcached==1.48 pytz==2012c recaptcha-client==1.0.6 --e git+https://github.com/wlanslovenija/simple-translation.git@94c5e5639532411e070e9746c0ebd802e142b208#egg=simple_translation-dev smmap==0.8.2 textile==2.1.5 wsgiref==0.1.2 +uwsgi==2.0.15 +svn+https://trac-hacks.org/svn/footnotemacro/trunk/#egg=tracfootnotemacro +git+https://github.com/mitar/trac-mathjax.git@e5b2bcbd8ec74685407c6fb2e71fb56cc2f47484#egg=mathjaxplugin +svn+https://trac-hacks.org/svn/dashessyntaxplugin/0.11/#egg=TracDashesSyntaxPlugin +hg+https://bitbucket.org/kisielk/tracmathplugin#egg=tracmath +git+https://github.com/herzbube/python-aprmd5.git#egg=python-aprmd5 +git+https://github.com/maccesch/cmsplugin-contact.git@ea95740655582faf603cb2f0f772f3600f952a6b#egg=cmsplugin-contact +git+https://github.com/stefanfoulis/cmsplugin-filer.git@9f2e5959c25b849ba64d4a6be10d6ccd7278e050#egg=cmsplugin_filer +git+https://github.com/mitar/django-cms.git@0bcf0409d5a052f136850cd03f6b54149a3983c5#egg=django_cms +git+https://github.com/mitar/django-filer.git#egg=django_filer +git+https://github.com/wlanslovenija/simple-translation.git@94c5e5639532411e070e9746c0ebd802e142b208#egg=simple_translation +git+https://github.com/wlanslovenija/cmsplugin-blog.git@0829d67e47934ab021206661ad5df7e7e1573b89#egg=cmsplugin_blog diff --git a/scripts/docker-init-db b/scripts/docker-init-db new file mode 100755 index 00000000..a40e5b96 --- /dev/null +++ b/scripts/docker-init-db @@ -0,0 +1,6 @@ +#!/bin/bash +su - postgres +scripts/docker-wait-pgsql +psql -d template1 -c 'create extension ip4r;' +psql --command "CREATE USER wlansi_cms WITH SUPERUSER PASSWORD 'mainpage';" +createdb -O wlansi_cms wlansi diff --git a/scripts/docker-run b/scripts/docker-run new file mode 100755 index 00000000..cecd20c3 --- /dev/null +++ b/scripts/docker-run @@ -0,0 +1,2 @@ +#!/bin/bash +exec /bin/bash -i -c "$*" \ No newline at end of file diff --git a/scripts/docker-run-db b/scripts/docker-run-db new file mode 100755 index 00000000..a9bf588e --- /dev/null +++ b/scripts/docker-run-db @@ -0,0 +1 @@ +#!/bin/bash diff --git a/scripts/docker-wait-pgsql b/scripts/docker-wait-pgsql new file mode 100755 index 00000000..c0acc349 --- /dev/null +++ b/scripts/docker-wait-pgsql @@ -0,0 +1,3 @@ +#!/bin/bash + +sleep 30s \ No newline at end of file diff --git a/scripts/migrate.py b/scripts/migrate.py new file mode 100755 index 00000000..ddd164b5 --- /dev/null +++ b/scripts/migrate.py @@ -0,0 +1,47 @@ +import os, subprocess, tempfile, urllib, tarfile, sqlite3 + +root = os.path.join(os.path.dirname(__file__), '..') + +manage_script = os.path.abspath(os.path.join(root, 'manage.py')) +database_file = os.path.abspath(os.path.join(root, 'mainpage', 'db.sqlite')) + +print "\nSetting up the database:\n" +if os.path.isfile(database_file): + print "Removing old database.\n" + os.remove(database_file) + +subprocess.check_call(('python', manage_script, 'syncdb', '--noinput')) +subprocess.check_call(('python', manage_script, 'migrate')) +subprocess.check_call(('python', manage_script, 'reset', '--noinput', 'contenttypes')) + +print "\nDownloading and importing database dump:\n" +tempFile = tempfile.NamedTemporaryFile(delete=False) +webFile = urllib.urlopen('http://bindist.wlan-si.net/data/dumpcms.yaml.bz2') +tempFile.write(webFile.read()) +webFile.close() +tempFile.close() +os.rename(tempFile.name, tempFile.name + '.yaml.bz2') +subprocess.check_call(('python', manage_script, 'loaddata', tempFile.name)) +os.remove(tempFile.name + '.yaml.bz2') + +(filename, _) = urllib.urlretrieve('http://bindist.wlan-si.net/data/dumpcms-nodewatcher.tar.bz2') +file = tarfile.open(filename) +file.extract('data.json') +subprocess.check_call(('python', manage_script, 'loaddata', 'data.json')) +os.remove('data.json') + +connection = sqlite3.connect(database_file) +cursor = connection.cursor() +cursor.execute("""UPDATE cmsplugin_blog_entrytitle SET author_id=1""") +connection.commit() +cursor.close() + +print "\nPreparing directories." + +for path in (('media', 'files'), ('media', 'thumbnails'), ('smedia', 'files'), ('smedia', 'thumbnails')): + try: + os.makedirs(os.path.join(root, 'mainpage', *path)) + except OSError: + pass + +print "\nAll done!" \ No newline at end of file