From bd6dd69524ff0988b10fa1c180381f21e97de3cc Mon Sep 17 00:00:00 2001 From: Christian Dresen <c.dresen@fh-muenster.de> Date: Fri, 9 Sep 2016 17:22:17 +0200 Subject: [PATCH] no message --- www/Dockerfile | 4 +- www/misc/entrypoint.sh | 2 +- www/nginx/nginx_warpinfra.conf | 17 ++- www/nginx/warpinfra.crt | 116 +++++++++++---- www/nginx/warpinfra.key | 135 +++++++++++------- www/run_dev.sh | 4 +- www/run_prod.sh | 1 + www/web/data/warpzone.db | 0 www/web/warpauth/migrations/0001_initial.py | 18 +-- .../migrations/0002_auto_20160821_1613.py | 56 ++++++++ .../migrations/0002_ldapuser_card_id.py | 22 +++ www/web/warpauth/models.py | 4 +- www/web/warpfood/migrations/0001_initial.py | 2 +- www/web/warpmain/migrations/0001_initial.py | 2 +- www/web/warppay/admin.py | 16 +++ www/web/warppay/migrations/0001_initial.py | 3 +- .../migrations/0002_auto_20160821_1701.py | 44 ++++++ .../migrations/0002_usercredit_card_id.py | 21 +++ .../migrations/0003_auto_20160821_1706.py | 28 ++++ .../migrations/0004_auto_20160909_1401.py | 20 +++ www/web/warppay/models.py | 31 ++-- www/web/warppay/urls.py | 4 + www/web/warppay/views.py | 83 ++++++++--- www/web/warpzone.db | Bin 76800 -> 79872 bytes 24 files changed, 507 insertions(+), 126 deletions(-) create mode 100644 www/web/data/warpzone.db create mode 100644 www/web/warpauth/migrations/0002_auto_20160821_1613.py create mode 100644 www/web/warpauth/migrations/0002_ldapuser_card_id.py create mode 100644 www/web/warppay/migrations/0002_auto_20160821_1701.py create mode 100644 www/web/warppay/migrations/0002_usercredit_card_id.py create mode 100644 www/web/warppay/migrations/0003_auto_20160821_1706.py create mode 100644 www/web/warppay/migrations/0004_auto_20160909_1401.py diff --git a/www/Dockerfile b/www/Dockerfile index b912afc..d430958 100644 --- a/www/Dockerfile +++ b/www/Dockerfile @@ -34,13 +34,13 @@ RUN rm /etc/nginx/sites-enabled/default RUN mkdir /opt/socket/ -COPY misc/ldapdb_base.py /usr/local/lib/python2.7/dist-packages/ldapdb/backends/ldap/base.py +COPY misc/ldapdb_base.py /usr/local/lib/python3.4/dist-packages/ldapdb/backends/ldap/base.py COPY misc/entrypoint.sh /opt/entrypoint.sh ADD web /opt/warpinfra/ ADD nginx /opt/nginx -EXPOSE 8000 +EXPOSE 8000 443 80 VOLUME ["/opt/nginx", "/opt/warpinfra"] diff --git a/www/misc/entrypoint.sh b/www/misc/entrypoint.sh index ac1f3e3..36f0bbd 100644 --- a/www/misc/entrypoint.sh +++ b/www/misc/entrypoint.sh @@ -5,7 +5,7 @@ cd /opt/warpinfra; python3 manage.py makemigrations python3 manage.py migrate python3 manage.py collectstatic --noinput - +cp -r /opt/warpinfra/static /opt/socket/ uwsgi --ini /opt/nginx/uwsgi.ini --py-autoreload 1 bash diff --git a/www/nginx/nginx_warpinfra.conf b/www/nginx/nginx_warpinfra.conf index 2c993ba..33bccbd 100644 --- a/www/nginx/nginx_warpinfra.conf +++ b/www/nginx/nginx_warpinfra.conf @@ -4,7 +4,22 @@ upstream django { server { listen 80; - return 301 https://$host$request_uri; + server_name _; + charset utf-8; + + client_max_body_size 100M; # adjust to taste + + location /static { + alias /opt/warpinfra/static; # your Django project's static files - amend as required + } + + # Finally, send all non-media requests to the Django server. + location / { + uwsgi_pass django; + include /opt/nginx/uwsgi_params; # the uwsgi_params file you installed + } + +# return 301 https://$host$request_uri; } # configuration of the server diff --git a/www/nginx/warpinfra.crt b/www/nginx/warpinfra.crt index 57cf97f..f50c90d 100644 --- a/www/nginx/warpinfra.crt +++ b/www/nginx/warpinfra.crt @@ -1,33 +1,87 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+s9A9vnnfhuMh +7TJQQ+/pEAY2cQomr2zQqZbkcbZe+7vSf9BnXZbW9WBq932YQI5LT9aopkJrUgGM +BdifjwXG5umIio4Jdp/HduBv7cg5S7aEABsFgNJ7eIRZsQ5J6Ho1ce1HhqcM8eEe +W/IiKBUxfzBkugZ59wk7v6SMcpGNiDKEt9osHEPVKC+2sKII6dA72iLnZg3UeQHa +2ixL4u92Dmvr3mq7Il4wGydvEMLXFYg1L20Qnvy3uOC0MpYG9iz6e5OK+FH4ytCE +vBkOsyWZ5v+//ufThDlQPuIygPXuYUq+cZaIeYpXmVaGtf2gV0XQmvypna6EcsHp +xnEP0tZNAgMBAAECggEAWfO1OTqcgAw/HOSmg+fXxUZyt8FQOXkrya0E6NKeZGU3 +bg4t/mPN3600gqAk1Ok2dV2+ciSiVb8DzcmAKZsr7WtEIszAPMSAj3SKXyF4/VWy +TMdD96+RGP5651e11rTa2FTZyJBCQb/iIRDbwLLJdGR7Ljf1EBiveUhnVHxCHdCc +/HOuGQnEJR1zOO8llTp36XN457ufqWWKSpS507gBmKdQiJDIooclaf71CIkJQBjh +j04O74RlTpTFzHyg/vzn5VDllwokgAJ3g9PgunBmHqCTQCF5chkkBKaubtKa2hx0 +JsXuTS8Zf6TBRNlUXxPC4SwkuUMdRFIcCAlSF8jK3QKBgQDkbtfGC8PAoYTIO6pK +tgRWSkdMkYG6UBoiLpH8qh7KDXT+CRcYdZNsDrH97VxaZlPUccL3Zrw68UVd50St +Vfdke/BD0lkmzjACou4Ebwmp4ZupEE8RghKP7MoWlNLqzLs4T60UzQHMyNIUUxkT +f6hWnuUBxasKkx4a+t2HWvXUrwKBgQDVt1SVcPcjr6VbFqs51LrzX4NU6d/b/il+ +uQS7QENzuCzVviGWAH59yQeVUSBB1xZweennIRnHhcpFYlqKA69VUwkyQb7uZZ4Y +iRvlOAdbBE156LsUE0vU6rFDyCNGvhz5ClKt+nXWoJscl1kY3S5qyPGhkrwBFlQT +594niKq7wwKBgQCt5Pt5lkckg1CzpUgTq9BNaCoyzan2DTh3wP/9WfwqUGg5Yu4j +/o2FewJgjar6Xl9+oEONVrYAIN9vhrivQ3wbEIZs+tpHQjsmJqYO1gCDRG3dG781 +UtGSou2Mlyqg982mJnFaHl46aL4UHtY+E7YwirFG0hVM7YXDgCnX+pSdnQKBgGnj +TrZIZTq6MSyDe8zIeORSg4iT5AVk1XxjAVQhkAoKy7QPYyamEgYSj35M1rWocwbB +cMHCpbo0sLZV99P/5WRaIulSp94IXR9892RHsWVIKXbod6CHuv/AVJnn1IqdcU92 +7OYkfTQdGR0+Y7etBu2DqCzMvfev73J5ZJmj3ivvAoGBAIz13UZrQoj7SdOjUZkJ +xGVjQKZbxJmEPCDXRoEjkPAmNCYiEtgMSD2xYuaSly1qyKwEwaevDzGBVO9Gf9QN +9Lmb4E9OKVehGpdPYT2+MPKO4i0dXfD5w3CP7SXE6zhzInmX5+qEcdAqVemz8QI0 +b2XE2w6nht6kQcMj7MrdCphv +-----END PRIVATE KEY----- + -----BEGIN CERTIFICATE----- -MIIFrTCCA5WgAwIBAgIJAKzK6RrFSz83MA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV -BAYTAkRFMQwwCgYDVQQIDANOUlcxETAPBgNVBAcMCE11ZW5zdGVyMRIwEAYDVQQK -DAlJVFNlY1RlYW0xEzARBgNVBAsMCkZsYWdIdW50ZXIxFDASBgNVBAMMC2ZsYWcu -aHVudGVyMB4XDTE1MTEyMDE5MTQ1OVoXDTE2MTExOTE5MTQ1OVowbTELMAkGA1UE -BhMCREUxDDAKBgNVBAgMA05SVzERMA8GA1UEBwwITXVlbnN0ZXIxEjAQBgNVBAoM -CUlUU2VjVGVhbTETMBEGA1UECwwKRmxhZ0h1bnRlcjEUMBIGA1UEAwwLZmxhZy5o -dW50ZXIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7toPOwQ1Xcqwk -VJItQC8wifoGeNk/E0k52XYVhvxXsZZI90n3CBp4LEIUMB6tPBwZ/mpI83hUu29f -yWkD1iexWFQF5uJJr4IlAjKjznYuvi7EzbNAQsFTmOYRvmTSVvnONx1PpZFRGEt8 -d4AmeztCMtk9JCV45xPeh7T00mxq7okOFsfrIlKfi7q0N5X1neMK4hgOuRqR+TE3 -MJvcsCKzIi/g1hvrly48OZqhnoBeQZHxbuT2i+jyl56sBjHqRswFxxBOwifEBNsP -V27Q9LWAi6tF1+RU6YYtfD4/en9sLEZ9y9U+Ch9kL82EaScIh234Sxb7VevAdJ3K -b+sL3Vum3JaOwejhTbzMtl2JkTy7knR2PUFW4ZA85MvE6/IChFoYSHVM/rsbUESn -nu08qAQ7AF2Yj/+sPCqc1BUEXxO6qYFeX+yXx4Fbl29xu3d5evbc2CHjVqGuGRyv -2V7XkuUHhvLmYV8AVUFHp1yLxhEZsMl4eSoPjVnNmY/WoljJeNjC7XmHwllsvqJt -59meh7FkD28DPducKnjfsKElqbc5pjeVi24302nHTS41eExalgHCd07j2sQVjXgF -C3BUP2Jl+tU2QV5/jRH2GCLMkhEwP/lPdK5usS9jXhJo0sb56M1ak4ECfavrxHHh -TSmgD9IaqP0ChOVIZ04DuxYxX2MURQIDAQABo1AwTjAdBgNVHQ4EFgQUC/Jkv7Vf -f/VAeY8zrBqvyWe+L4cwHwYDVR0jBBgwFoAUC/Jkv7Vff/VAeY8zrBqvyWe+L4cw -DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAeTtgmsIFI6LgxbyAIc/8 -dZXmP9DKXZkv17UEAKoJC/d+IOqDogXoeRhbo2cLmIXCE5cmhp+xsXZnxke4Oq39 -az6eBlcwaPUUTlzP5MiIqDpzbhi6sjQhp5FmH2/RtFkVzjpNm2NP+7IW1lAxx3is -qxXBCVXYXmiHL6rW5BwNrlGDqwUhFDVZJL4QIBENqwMC7qTubYiukBdaqWz8uTYs -WFOo73fYqG/SNbFifq78czTRoXTTr085Yxnprr4whuqTPpmBd42IUzOxRHF5ICPX -316S6X3b65mTzzz15p1KquUe+VsULnUZTtOOeyIqpm8VWSu4EoKK0c2w8bZkgImR -ttAMRnA4S00ZuhQ1CnJgMX/54krJWdswJH7O+fTsu7A7jy2PhADbyhPx61pVyH2H -zYm+7RPlvGgdkqvdyO6EeZN1RRIPkyUb+6bbCwHPIDRc+DXh5dq4w0wN7vctMMri -eo+OrxK97O4egmg67J3XCYBCmPsnH0vaV/UTOgmyeo7Y8NqMulUOCVz1PhidW0r2 -M7dRB7958G6Z1tuuFXr0Y+88RDyTHdu9XqCLHjLAjF2PIqhPHZ59KnHVmb4bWICK -4D3rdOS0woeiXCxUQxekBh8ZMBIzyeUONrkYykBwV5sZrMZt26GGMlNyJ7uYcFzW -MsRX8eO4RytlNdVSGVSrLpQ= +MIIE/jCCA+agAwIBAgISA1hyjstoi3F5Iclnmu5EQMScMA0GCSqGSIb3DQEBCwUA +MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD +ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjA4MjgxNDI5MDBaFw0x +NjExMjYxNDI5MDBaMBgxFjAUBgNVBAMTDWRldi5keWhvc3QuZGUwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+s9A9vnnfhuMh7TJQQ+/pEAY2cQomr2zQ +qZbkcbZe+7vSf9BnXZbW9WBq932YQI5LT9aopkJrUgGMBdifjwXG5umIio4Jdp/H +duBv7cg5S7aEABsFgNJ7eIRZsQ5J6Ho1ce1HhqcM8eEeW/IiKBUxfzBkugZ59wk7 +v6SMcpGNiDKEt9osHEPVKC+2sKII6dA72iLnZg3UeQHa2ixL4u92Dmvr3mq7Il4w +GydvEMLXFYg1L20Qnvy3uOC0MpYG9iz6e5OK+FH4ytCEvBkOsyWZ5v+//ufThDlQ +PuIygPXuYUq+cZaIeYpXmVaGtf2gV0XQmvypna6EcsHpxnEP0tZNAgMBAAGjggIO +MIICCjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF +BwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFHahdg/WaDq0yPz59/SZOwb9HmLX +MB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMHAGCCsGAQUFBwEBBGQw +YjAvBggrBgEFBQcwAYYjaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9y +Zy8wLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5v +cmcvMBgGA1UdEQQRMA+CDWRldi5keWhvc3QuZGUwgf4GA1UdIASB9jCB8zAIBgZn +gQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3Bz +LmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmlj +YXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBh +bmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGlj +eSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzAN +BgkqhkiG9w0BAQsFAAOCAQEAl598A9BClTRIh84bzUTSSGu8nym9IOpl5and/gCX +IsB1w66ZhJDcJC21mXkQWRSSysenwX0zayRaNs2KMZviyr32RTTfNPJHXFROYiNl +G0iQodNvEhkF05/QEPS2DvFWqwU9nkxZ9byzzvciwFVHh1RqDzmGUqQTyu6pAqBt +UZIjFulDL/zjLduIz9326hPGv/9qiEbumPpH7WTxUesaBrXXgrCSDkrXrVwk5V+b +hGU5s/gEsrAxqQgFVqhrrnc8fK40kcqF45i5K2mrhFMSNtEuI7gwrKbs+vulZpJY +TM2a4Gtibkew5XwpaC7aED6QLNux9jQdQ3lqsaSLj4Y9dQ== -----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow +SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT +GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF +q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 +SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 +Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA +a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj +/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG +CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv +bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k +c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw +VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC +ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz +MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu +Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF +AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo +uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ +wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu +X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG +PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 +KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== +-----END CERTIFICATE----- + diff --git a/www/nginx/warpinfra.key b/www/nginx/warpinfra.key index fb31d8d..f50c90d 100644 --- a/www/nginx/warpinfra.key +++ b/www/nginx/warpinfra.key @@ -1,52 +1,87 @@ -----BEGIN PRIVATE KEY----- -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 -su7ZYG7K5L+RRjrWZagNh8X2s6qeaA== +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+s9A9vnnfhuMh +7TJQQ+/pEAY2cQomr2zQqZbkcbZe+7vSf9BnXZbW9WBq932YQI5LT9aopkJrUgGM +BdifjwXG5umIio4Jdp/HduBv7cg5S7aEABsFgNJ7eIRZsQ5J6Ho1ce1HhqcM8eEe +W/IiKBUxfzBkugZ59wk7v6SMcpGNiDKEt9osHEPVKC+2sKII6dA72iLnZg3UeQHa +2ixL4u92Dmvr3mq7Il4wGydvEMLXFYg1L20Qnvy3uOC0MpYG9iz6e5OK+FH4ytCE +vBkOsyWZ5v+//ufThDlQPuIygPXuYUq+cZaIeYpXmVaGtf2gV0XQmvypna6EcsHp +xnEP0tZNAgMBAAECggEAWfO1OTqcgAw/HOSmg+fXxUZyt8FQOXkrya0E6NKeZGU3 +bg4t/mPN3600gqAk1Ok2dV2+ciSiVb8DzcmAKZsr7WtEIszAPMSAj3SKXyF4/VWy +TMdD96+RGP5651e11rTa2FTZyJBCQb/iIRDbwLLJdGR7Ljf1EBiveUhnVHxCHdCc +/HOuGQnEJR1zOO8llTp36XN457ufqWWKSpS507gBmKdQiJDIooclaf71CIkJQBjh +j04O74RlTpTFzHyg/vzn5VDllwokgAJ3g9PgunBmHqCTQCF5chkkBKaubtKa2hx0 +JsXuTS8Zf6TBRNlUXxPC4SwkuUMdRFIcCAlSF8jK3QKBgQDkbtfGC8PAoYTIO6pK +tgRWSkdMkYG6UBoiLpH8qh7KDXT+CRcYdZNsDrH97VxaZlPUccL3Zrw68UVd50St +Vfdke/BD0lkmzjACou4Ebwmp4ZupEE8RghKP7MoWlNLqzLs4T60UzQHMyNIUUxkT +f6hWnuUBxasKkx4a+t2HWvXUrwKBgQDVt1SVcPcjr6VbFqs51LrzX4NU6d/b/il+ +uQS7QENzuCzVviGWAH59yQeVUSBB1xZweennIRnHhcpFYlqKA69VUwkyQb7uZZ4Y +iRvlOAdbBE156LsUE0vU6rFDyCNGvhz5ClKt+nXWoJscl1kY3S5qyPGhkrwBFlQT +594niKq7wwKBgQCt5Pt5lkckg1CzpUgTq9BNaCoyzan2DTh3wP/9WfwqUGg5Yu4j +/o2FewJgjar6Xl9+oEONVrYAIN9vhrivQ3wbEIZs+tpHQjsmJqYO1gCDRG3dG781 +UtGSou2Mlyqg982mJnFaHl46aL4UHtY+E7YwirFG0hVM7YXDgCnX+pSdnQKBgGnj +TrZIZTq6MSyDe8zIeORSg4iT5AVk1XxjAVQhkAoKy7QPYyamEgYSj35M1rWocwbB +cMHCpbo0sLZV99P/5WRaIulSp94IXR9892RHsWVIKXbod6CHuv/AVJnn1IqdcU92 +7OYkfTQdGR0+Y7etBu2DqCzMvfev73J5ZJmj3ivvAoGBAIz13UZrQoj7SdOjUZkJ +xGVjQKZbxJmEPCDXRoEjkPAmNCYiEtgMSD2xYuaSly1qyKwEwaevDzGBVO9Gf9QN +9Lmb4E9OKVehGpdPYT2+MPKO4i0dXfD5w3CP7SXE6zhzInmX5+qEcdAqVemz8QI0 +b2XE2w6nht6kQcMj7MrdCphv -----END PRIVATE KEY----- + +-----BEGIN CERTIFICATE----- +MIIE/jCCA+agAwIBAgISA1hyjstoi3F5Iclnmu5EQMScMA0GCSqGSIb3DQEBCwUA +MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD +ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjA4MjgxNDI5MDBaFw0x +NjExMjYxNDI5MDBaMBgxFjAUBgNVBAMTDWRldi5keWhvc3QuZGUwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+s9A9vnnfhuMh7TJQQ+/pEAY2cQomr2zQ +qZbkcbZe+7vSf9BnXZbW9WBq932YQI5LT9aopkJrUgGMBdifjwXG5umIio4Jdp/H +duBv7cg5S7aEABsFgNJ7eIRZsQ5J6Ho1ce1HhqcM8eEeW/IiKBUxfzBkugZ59wk7 +v6SMcpGNiDKEt9osHEPVKC+2sKII6dA72iLnZg3UeQHa2ixL4u92Dmvr3mq7Il4w +GydvEMLXFYg1L20Qnvy3uOC0MpYG9iz6e5OK+FH4ytCEvBkOsyWZ5v+//ufThDlQ +PuIygPXuYUq+cZaIeYpXmVaGtf2gV0XQmvypna6EcsHpxnEP0tZNAgMBAAGjggIO +MIICCjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF +BwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFHahdg/WaDq0yPz59/SZOwb9HmLX +MB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMHAGCCsGAQUFBwEBBGQw +YjAvBggrBgEFBQcwAYYjaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9y +Zy8wLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5v +cmcvMBgGA1UdEQQRMA+CDWRldi5keWhvc3QuZGUwgf4GA1UdIASB9jCB8zAIBgZn +gQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3Bz +LmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmlj +YXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBh +bmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGlj +eSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzAN +BgkqhkiG9w0BAQsFAAOCAQEAl598A9BClTRIh84bzUTSSGu8nym9IOpl5and/gCX +IsB1w66ZhJDcJC21mXkQWRSSysenwX0zayRaNs2KMZviyr32RTTfNPJHXFROYiNl +G0iQodNvEhkF05/QEPS2DvFWqwU9nkxZ9byzzvciwFVHh1RqDzmGUqQTyu6pAqBt +UZIjFulDL/zjLduIz9326hPGv/9qiEbumPpH7WTxUesaBrXXgrCSDkrXrVwk5V+b +hGU5s/gEsrAxqQgFVqhrrnc8fK40kcqF45i5K2mrhFMSNtEuI7gwrKbs+vulZpJY +TM2a4Gtibkew5XwpaC7aED6QLNux9jQdQ3lqsaSLj4Y9dQ== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow +SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT +GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF +q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 +SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 +Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA +a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj +/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG +CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv +bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k +c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw +VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC +ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz +MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu +Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF +AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo +uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ +wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu +X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG +PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 +KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== +-----END CERTIFICATE----- + diff --git a/www/run_dev.sh b/www/run_dev.sh index b32520a..476fcd0 100644 --- a/www/run_dev.sh +++ b/www/run_dev.sh @@ -6,10 +6,10 @@ docker rm warpinfra docker run \ -v $SCRIPTPATH/web:/opt/warpinfra \ - -v $SCRIPTPATH/nginx:/opt/nginx \ + -v $SCRIPTPATH/nginx:/opt/nginx \ -v $SCRIPTPATH/conf/config.example.ini:/etc/warpinfra/config.ini \ --link ldap-service:ldap \ --name warpinfra \ - -p 8000:443 \ + -p 8000:80 \ -itd \ warpinfra diff --git a/www/run_prod.sh b/www/run_prod.sh index d9cb938..ac4e649 100644 --- a/www/run_prod.sh +++ b/www/run_prod.sh @@ -9,6 +9,7 @@ docker run \ --link ldap-service:ldap \ --name warpinfra \ --volume /tmp/warpinfra:/opt/socket \ + --volume /opt/warpinfra/data:/opt/database/ -p 8000:443 \ -itd \ warpinfra diff --git a/www/web/data/warpzone.db b/www/web/data/warpzone.db new file mode 100644 index 0000000..e69de29 diff --git a/www/web/warpauth/migrations/0001_initial.py b/www/web/warpauth/migrations/0001_initial.py index d9bbae0..495e7e8 100644 --- a/www/web/warpauth/migrations/0001_initial.py +++ b/www/web/warpauth/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-08-18 15:07 +# Generated by Django 1.9 on 2016-08-21 16:21 from __future__ import unicode_literals from django.db import migrations, models @@ -18,9 +18,9 @@ class Migration(migrations.Migration): name='LdapGroup', fields=[ ('dn', models.CharField(max_length=200)), - ('gid', ldapdb.models.fields.IntegerField(db_column=b'gidNumber', unique=True)), - ('name', ldapdb.models.fields.CharField(db_column=b'cn', max_length=200, primary_key=True, serialize=False)), - ('members', ldapdb.models.fields.ListField(db_column=b'memberUid')), + ('gid', ldapdb.models.fields.IntegerField(db_column='gidNumber', unique=True)), + ('name', ldapdb.models.fields.CharField(db_column='cn', max_length=200, primary_key=True, serialize=False)), + ('members', ldapdb.models.fields.ListField(db_column='memberUid')), ], options={ 'abstract': False, @@ -30,11 +30,11 @@ class Migration(migrations.Migration): name='LdapUser', fields=[ ('dn', models.CharField(max_length=200)), - ('uid', ldapdb.models.fields.CharField(db_column=b'uid', max_length=200, primary_key=True, serialize=False, unique=True)), - ('first_name', ldapdb.models.fields.CharField(db_column=b'givenName', max_length=200)), - ('last_name', ldapdb.models.fields.CharField(db_column=b'sn', max_length=200)), - ('email', ldapdb.models.fields.CharField(db_column=b'description', max_length=200)), - ('cn', ldapdb.models.fields.CharField(db_column=b'cn', max_length=200)), + ('uid', ldapdb.models.fields.CharField(db_column='uid', max_length=200, primary_key=True, serialize=False, unique=True)), + ('first_name', ldapdb.models.fields.CharField(db_column='givenName', max_length=200)), + ('last_name', ldapdb.models.fields.CharField(db_column='sn', max_length=200)), + ('email', ldapdb.models.fields.CharField(db_column='mail', max_length=200)), + ('cn', ldapdb.models.fields.CharField(db_column='cn', max_length=200)), ], options={ 'abstract': False, diff --git a/www/web/warpauth/migrations/0002_auto_20160821_1613.py b/www/web/warpauth/migrations/0002_auto_20160821_1613.py new file mode 100644 index 0000000..e83f519 --- /dev/null +++ b/www/web/warpauth/migrations/0002_auto_20160821_1613.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-08-21 16:13 +from __future__ import unicode_literals + +from django.db import migrations +import ldapdb.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('warpauth', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='ldapgroup', + name='gid', + field=ldapdb.models.fields.IntegerField(db_column='gidNumber', unique=True), + ), + migrations.AlterField( + model_name='ldapgroup', + name='members', + field=ldapdb.models.fields.ListField(db_column='memberUid'), + ), + migrations.AlterField( + model_name='ldapgroup', + name='name', + field=ldapdb.models.fields.CharField(db_column='cn', max_length=200, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='ldapuser', + name='cn', + field=ldapdb.models.fields.CharField(db_column='cn', max_length=200), + ), + migrations.AlterField( + model_name='ldapuser', + name='email', + field=ldapdb.models.fields.CharField(db_column='mail', max_length=200), + ), + migrations.AlterField( + model_name='ldapuser', + name='first_name', + field=ldapdb.models.fields.CharField(db_column='givenName', max_length=200), + ), + migrations.AlterField( + model_name='ldapuser', + name='last_name', + field=ldapdb.models.fields.CharField(db_column='sn', max_length=200), + ), + migrations.AlterField( + model_name='ldapuser', + name='uid', + field=ldapdb.models.fields.CharField(db_column='uid', max_length=200, primary_key=True, serialize=False, unique=True), + ), + ] diff --git a/www/web/warpauth/migrations/0002_ldapuser_card_id.py b/www/web/warpauth/migrations/0002_ldapuser_card_id.py new file mode 100644 index 0000000..95cb90c --- /dev/null +++ b/www/web/warpauth/migrations/0002_ldapuser_card_id.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-08-21 16:52 +from __future__ import unicode_literals + +from django.db import migrations +import ldapdb.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('warpauth', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='ldapuser', + name='card_id', + field=ldapdb.models.fields.CharField(db_column='pager', default=0, max_length=200), + preserve_default=False, + ), + ] diff --git a/www/web/warpauth/models.py b/www/web/warpauth/models.py index 3f4bae7..e783a92 100644 --- a/www/web/warpauth/models.py +++ b/www/web/warpauth/models.py @@ -22,7 +22,7 @@ class LdapUser(ldapdb.models.Model): last_name = CharField(db_column='sn', max_length=200) email = CharField(db_column='mail', max_length=200) cn = CharField(db_column='cn', max_length=200) - + card_id = CharField(db_column='pager', max_length=200) def __str__(self): return self.uid @@ -34,7 +34,7 @@ class LdapUser(ldapdb.models.Model): class LdapUserForm(ModelForm): class Meta: model = LdapUser - fields = ['first_name', 'last_name', 'email'] + fields = ['first_name', 'last_name', 'email','card_id'] class LdapGroup(ldapdb.models.Model): diff --git a/www/web/warpfood/migrations/0001_initial.py b/www/web/warpfood/migrations/0001_initial.py index b058e2f..0a5a045 100644 --- a/www/web/warpfood/migrations/0001_initial.py +++ b/www/web/warpfood/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-08-18 15:07 +# Generated by Django 1.9 on 2016-08-21 16:20 from __future__ import unicode_literals from django.db import migrations, models diff --git a/www/web/warpmain/migrations/0001_initial.py b/www/web/warpmain/migrations/0001_initial.py index e9f0080..110b564 100644 --- a/www/web/warpmain/migrations/0001_initial.py +++ b/www/web/warpmain/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-08-18 15:07 +# Generated by Django 1.9 on 2016-08-21 16:27 from __future__ import unicode_literals from django.db import migrations, models diff --git a/www/web/warppay/admin.py b/www/web/warppay/admin.py index e69de29..5f28e74 100644 --- a/www/web/warppay/admin.py +++ b/www/web/warppay/admin.py @@ -0,0 +1,16 @@ +from django.contrib import admin +from warppay.models import * + +# Register your models here. + +@admin.register(ProductCategory) +class ProductCategoryAdmin(admin.ModelAdmin): + pass + +@admin.register(Product) +class ProductAdmin(admin.ModelAdmin): + pass + +@admin.register(UserCredit) +class UserCreditAdmin(admin.ModelAdmin): + pass \ No newline at end of file diff --git a/www/web/warppay/migrations/0001_initial.py b/www/web/warppay/migrations/0001_initial.py index 8bb050b..03b54ba 100644 --- a/www/web/warppay/migrations/0001_initial.py +++ b/www/web/warppay/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-08-18 15:07 +# Generated by Django 1.9 on 2016-08-21 16:21 from __future__ import unicode_literals from django.db import migrations, models @@ -28,6 +28,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('uid', models.CharField(max_length=100, unique=True)), + ('card_id', models.IntegerField()), ('credit', models.FloatField()), ], ), diff --git a/www/web/warppay/migrations/0002_auto_20160821_1701.py b/www/web/warppay/migrations/0002_auto_20160821_1701.py new file mode 100644 index 0000000..e8d2e68 --- /dev/null +++ b/www/web/warppay/migrations/0002_auto_20160821_1701.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-08-21 17:01 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('warppay', '0001_initial'), + ] + + operations = [ + migrations.RenameField( + model_name='product', + old_name='user', + new_name='name', + ), + migrations.RemoveField( + model_name='product', + name='created', + ), + migrations.RemoveField( + model_name='product', + name='message', + ), + migrations.RemoveField( + model_name='product', + name='title', + ), + migrations.AddField( + model_name='product', + name='count', + field=models.IntegerField(default=0), + preserve_default=False, + ), + migrations.AddField( + model_name='product', + name='price', + field=models.FloatField(default=0), + preserve_default=False, + ), + ] diff --git a/www/web/warppay/migrations/0002_usercredit_card_id.py b/www/web/warppay/migrations/0002_usercredit_card_id.py new file mode 100644 index 0000000..bcb14cd --- /dev/null +++ b/www/web/warppay/migrations/0002_usercredit_card_id.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-08-21 16:12 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('warppay', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='usercredit', + name='card_id', + field=models.IntegerField(default=0), + preserve_default=False, + ), + ] diff --git a/www/web/warppay/migrations/0003_auto_20160821_1706.py b/www/web/warppay/migrations/0003_auto_20160821_1706.py new file mode 100644 index 0000000..d834e1b --- /dev/null +++ b/www/web/warppay/migrations/0003_auto_20160821_1706.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-08-21 17:06 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('warppay', '0002_auto_20160821_1701'), + ] + + operations = [ + migrations.CreateModel( + name='ProductCategory', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, unique=True)), + ], + ), + migrations.AddField( + model_name='product', + name='category', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='warppay.ProductCategory'), + ), + ] diff --git a/www/web/warppay/migrations/0004_auto_20160909_1401.py b/www/web/warppay/migrations/0004_auto_20160909_1401.py new file mode 100644 index 0000000..4d8597b --- /dev/null +++ b/www/web/warppay/migrations/0004_auto_20160909_1401.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-09-09 14:01 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('warppay', '0003_auto_20160821_1706'), + ] + + operations = [ + migrations.AlterField( + model_name='usercredit', + name='card_id', + field=models.CharField(max_length=10, unique=True), + ), + ] diff --git a/www/web/warppay/models.py b/www/web/warppay/models.py index c462cfa..edda802 100644 --- a/www/web/warppay/models.py +++ b/www/web/warppay/models.py @@ -4,22 +4,35 @@ from django.db import models from rest_framework import routers, serializers, viewsets from warpauth.models import LdapUser - +class ProductCategory(models.Model): + name = models.CharField(max_length=100, unique=True) + def __str__(self): + return self.name + class Product(models.Model): - user = models.CharField(max_length=100, null=True) - title = models.CharField(max_length=100) - message = models.TextField() - created = models.DateTimeField(auto_now_add=True) + name = models.CharField(max_length=100, null=True) + price = models.FloatField() + category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE, null=True) + count = models.IntegerField() def __str__(self): - return self.title + return self.name + +class ProductSerializer(serializers.ModelSerializer): + category = serializers.StringRelatedField() + class Meta: + model = Product + fields = ['id', 'name', 'price', 'category', 'count'] + class UserCredit(models.Model): uid = models.CharField(max_length=100,unique=True) + card_id = models.CharField(max_length=10, unique=True) credit = models.FloatField() + def __str__(self): + return self.uid - -class UserCreditSerializer(serializers.HyperlinkedModelSerializer): +class UserCreditSerializer(serializers.ModelSerializer): class Meta: model = UserCredit - fields = ['uid', 'credit'] + fields = ['uid', 'card_id', 'credit'] diff --git a/www/web/warppay/urls.py b/www/web/warppay/urls.py index 157ac62..ac022ce 100644 --- a/www/web/warppay/urls.py +++ b/www/web/warppay/urls.py @@ -4,4 +4,8 @@ from warppay import views urlpatterns = [ #url(r'^api/', include(router.urls)), url(r'^api/users/$', views.user_list), + url(r'^api/users/(?P<user_id>\w+)/$', views.user_list), + url(r'^api/products/$', views.product_list), + url(r'^api/gen_token/$', views.gen_token), + ] diff --git a/www/web/warppay/views.py b/www/web/warppay/views.py index 42db93a..2cae82a 100644 --- a/www/web/warppay/views.py +++ b/www/web/warppay/views.py @@ -1,41 +1,92 @@ from django.db import IntegrityError from warpauth.models import LdapUser -from warppay.models import UserCredit, UserCreditSerializer +from warppay.models import UserCredit, UserCreditSerializer, Product, ProductSerializer from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.decorators import authentication_classes, permission_classes +from rest_framework.authtoken.models import Token +from django.contrib.auth.models import User +from rest_framework import status -# from rest_framework.authtoken.models import Token -# token = Token.objects.create(user=request.user) # logging.getLogger('main').info(token.key) -@api_view(['GET', 'POST', 'PUT']) -@authentication_classes((TokenAuthentication,)) -@permission_classes((IsAuthenticated,)) -def user_list(request): +@api_view(['GET', 'PUT']) +#@authentication_classes((TokenAuthentication,)) +#@permission_classes((IsAuthenticated,)) +def product_list(request): if request.method == 'GET': - sync_users() - users = UserCredit.objects.all() - serializer = UserCreditSerializer(users, many=True) + products = Product.objects.all() + serializer = ProductSerializer(products,context={'request': request}, many=True) return Response(serializer.data) - elif request.method == 'POST': - + elif request.method == 'PUT': return Response() + return Response() + + +@api_view(['GET']) +def gen_token(request): + if request.method == 'GET': + token = Token.objects.create(user=User.objects.get(username='api')) + return Response(token) + return Response() + +@api_view(['GET', 'PUT', 'POST']) +#@authentication_classes((TokenAuthentication,)) +#@permission_classes((IsAuthenticated,)) +def user_list(request, user_id = 0): + if request.method == 'GET': + sync_users() + if not user_id: + users = UserCredit.objects.all() + serializer = UserCreditSerializer(users, many=True) + else: + user = UserCredit.objects.get(uid=user_id) + serializer = UserCreditSerializer(user) + return Response(serializer.data) elif request.method == 'PUT': + if not user_id: + return Response(status=status.HTTP_406_NOT_ACCEPTABLE) + sync_users() try: - UserCredit.objects.get(uid=request.data['uid']) + user = UserCredit.objects.get(uid=user_id) + if "credit" in request.data: + user.credit = request.data['credit'] + if "card_id" in request.data: + user.card_id = request.data['card_id'] + user.save(); + return Response(UserCreditSerializer(user).data) except UserCredit.DoesNotExist: - u = UserCredit(uid=request.data['uid'], credit=0.0) - u.save() + return Response(status=status.HTTP_404_NOT_FOUND) return Response() + + elif request.method == 'POST': + card_id="" + if not 'uid' in request.data: + return Response(status=status.HTTP_406_NOT_ACCEPTABLE) + if 'card_id' in request.data: + card_id = request.data['card_id'] + u = UserCredit(uid=request.data['uid'], card_id=card_id, credit=0.0) + try: + u.save() + state=status.HTTP_201_CREATED + except IntegrityError as e: + u = UserCredit.objects.get(uid=request.data['uid']) + state=status.HTTP_409_CONFLICT + + serializer = UserCreditSerializer(u) + return Response(serializer.data, status=state) + return Response() + def sync_users(): for user in LdapUser.objects.all(): try: - u = UserCredit(uid=user, credit=0.0) + u = UserCredit(uid=user.uid, card_id=user.card_id, credit=0.0) u.save() except IntegrityError: pass + except: + pass diff --git a/www/web/warpzone.db b/www/web/warpzone.db index 81069c749d4e6fcb5e38e98ea3925bf3623b89e0..2b253a2ff47ee5cbffbec87ac395208a4e2984fe 100644 GIT binary patch literal 79872 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 literal 76800 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 A`2YX_ -- GitLab