From 7b98e2a8b6845d272b0999b6409191c553429cf2 Mon Sep 17 00:00:00 2001 From: garoller Date: Wed, 27 Mar 2019 10:03:51 -0400 Subject: [PATCH 01/33] Basic detail petition view --- index/models.py | 4 ++++ index/templates/detail.html | 11 +++++++++++ index/templates/index.html | 2 +- index/urls.py | 1 + index/views.py | 5 +++++ 5 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 index/templates/detail.html diff --git a/index/models.py b/index/models.py index f4640eb..a84f57a 100644 --- a/index/models.py +++ b/index/models.py @@ -1,5 +1,6 @@ from django.db import models from django.utils import timezone +from django.urls import reverse # Creates a tag, there can be at most three in a single petition class Tag(models.Model): @@ -187,3 +188,6 @@ def check_tags(self): # Add tag to a petition, there can be at most three in a single petition # def add_tag (self): + + def get_url(self): + return reverse('petition-detail', args=[str(self.ID)]) diff --git a/index/templates/detail.html b/index/templates/detail.html new file mode 100644 index 0000000..27b3c75 --- /dev/null +++ b/index/templates/detail.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% block title %} {{ petition.title }} {% endblock %} + +{% block content %} +
+

{{ petition.title }}

+ +

{{ petition.description }}

+ +
+{% endblock %} \ No newline at end of file diff --git a/index/templates/index.html b/index/templates/index.html index b061406..dcfc2f5 100644 --- a/index/templates/index.html +++ b/index/templates/index.html @@ -18,7 +18,7 @@

Make your voice heard by the RPI Student Senate and the campus community.
-
{{ petition.title }}
+
{{ petition.title }}
{{ petition.signatures.count }} signatures
{% for tag in petition.tags.all %} {{ tag }}
diff --git a/index/urls.py b/index/urls.py index 96cc5ef..addf613 100644 --- a/index/urls.py +++ b/index/urls.py @@ -5,4 +5,5 @@ path("", views.index, name="index"), path("create/", views.create, name="create"), path("all/", views.all, name="all"), + path("petition/", views.petition_detail, name="petition-detail"), ] diff --git a/index/views.py b/index/views.py index 2edb6a7..f9bb6f7 100644 --- a/index/views.py +++ b/index/views.py @@ -18,3 +18,8 @@ def create(request): form = CreatePetitionForm() context = {"form": form} return render(request, "create.html", context=context) + +def petition_detail(request, pk): + petition = Petition.objects.get(pk=pk) + context = {"petition": petition} + return render(request, "detail.html", context=context) From f15ac7241e31f6d5b6e3bb0ce521e1a4c7f746be Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 2 Apr 2019 11:19:27 -0400 Subject: [PATCH 02/33] Add content and style to detail view --- index/static/petition/style.css | 38 ++++++++++++++++++++++++- index/templates/detail.html | 49 +++++++++++++++++++++++++++++++-- index/views.py | 24 ++++++++++++++-- 3 files changed, 106 insertions(+), 5 deletions(-) diff --git a/index/static/petition/style.css b/index/static/petition/style.css index 40da3dc..ee1c24f 100644 --- a/index/static/petition/style.css +++ b/index/static/petition/style.css @@ -48,10 +48,41 @@ body { max-width: 60%; } -.header { +.header, .info, .description, .signatures { margin-left: 40px; margin-bottom: 20px; + margin-top: 10px; + +} + +.detail { + /* text-align: center; */ + /* margin-left: 40px; */ + margin-top: 50px; + padding-left: 20px; +} + +.parent { + display: flex; + /* align-items: center; */ } + +.left { + margin-right: auto; + flex-grow: 1; + padding: 20px; +} + +.right { + margin-left: auto; + min-width: 30%; + padding: 20px; +} + +.info { + /* max-width: 50%; */ +} + .card-title a { color: #ed1c24; } @@ -91,3 +122,8 @@ body { .card { min-height: 175px; } + +#sign-btn { + background-color: #ed1c24; + color: white; +} \ No newline at end of file diff --git a/index/templates/detail.html b/index/templates/detail.html index 27b3c75..81dc510 100644 --- a/index/templates/detail.html +++ b/index/templates/detail.html @@ -3,9 +3,54 @@ {% block content %}
-

{{ petition.title }}

+
+

{{ petition.title }}

+
Created by {{ petition.author.rcs_id }}
+
+ +
+
+
+
Description
+

{{ petition.description }}

+
+ +
+
Signed by
+ {% for signature in signatures %} +

signature.signer.initials

+ {% empty %} +

No signatures yet

+ {% endfor %} +
+
+ +
+
+
Take action
+ +
+ +
+
{{signatures.count}} / {{petition.expected_sig}} Signatures
+
+
+
+
+ +
+
Status
+
{{status}}
+
+ +
+
Expires
+
{{ date|date:'M d, Y' }}
+
+
+ + -

{{ petition.description }}

{% endblock %} \ No newline at end of file diff --git a/index/views.py b/index/views.py index f9bb6f7..fbb728d 100644 --- a/index/views.py +++ b/index/views.py @@ -1,5 +1,6 @@ from django.shortcuts import render from django.views import generic +from django.utils import timezone from .forms import CreatePetitionForm from .models import Petition, Tag @@ -13,7 +14,6 @@ def index(request): def all(request): return render(request, "all.html") - def create(request): form = CreatePetitionForm() context = {"form": form} @@ -21,5 +21,25 @@ def create(request): def petition_detail(request, pk): petition = Petition.objects.get(pk=pk) - context = {"petition": petition} + signatures = petition.signatures.all() + + status = "Goal not met" + if (petition.check_enough_sigs()): + status = "Goal met" + + expiration_date = petition.created_date + timezone.timedelta(days=365) + + context = {"petition": petition, "signatures": signatures, "status": status, "date": expiration_date} return render(request, "detail.html", context=context) + +# def add_signature(request, pk, user_pk): +# petition = Petition.objects.get(pk=pk) +# user = User.objects.get(pk=user_pk) +# new_signature = Signature.create(user) +# new_signature.save() + +# petition.signatures.add(new_signature) +# petition.save() + +# return petition_detail() + From 2bfc21c2de93df4e3c27415a99fa36ba8faa71e0 Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 2 Apr 2019 11:22:34 -0400 Subject: [PATCH 03/33] Run python black --- index/models.py | 4 ++-- index/views.py | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/index/models.py b/index/models.py index a84f57a..e8c2475 100644 --- a/index/models.py +++ b/index/models.py @@ -188,6 +188,6 @@ def check_tags(self): # Add tag to a petition, there can be at most three in a single petition # def add_tag (self): - + def get_url(self): - return reverse('petition-detail', args=[str(self.ID)]) + return reverse("petition-detail", args=[str(self.ID)]) diff --git a/index/views.py b/index/views.py index fbb728d..3aa69ad 100644 --- a/index/views.py +++ b/index/views.py @@ -14,24 +14,32 @@ def index(request): def all(request): return render(request, "all.html") + def create(request): form = CreatePetitionForm() context = {"form": form} return render(request, "create.html", context=context) + def petition_detail(request, pk): petition = Petition.objects.get(pk=pk) signatures = petition.signatures.all() status = "Goal not met" - if (petition.check_enough_sigs()): + if petition.check_enough_sigs(): status = "Goal met" - + expiration_date = petition.created_date + timezone.timedelta(days=365) - context = {"petition": petition, "signatures": signatures, "status": status, "date": expiration_date} + context = { + "petition": petition, + "signatures": signatures, + "status": status, + "date": expiration_date, + } return render(request, "detail.html", context=context) + # def add_signature(request, pk, user_pk): # petition = Petition.objects.get(pk=pk) # user = User.objects.get(pk=user_pk) @@ -42,4 +50,3 @@ def petition_detail(request, pk): # petition.save() # return petition_detail() - From 1f5350e7c6f3eff846cd851a8fbe95ecb6c4933e Mon Sep 17 00:00:00 2001 From: garoller Date: Fri, 5 Apr 2019 13:03:54 -0400 Subject: [PATCH 04/33] Install django cas --- Pipfile | 1 + Pipfile.lock | 151 +++++++++++++++++++++++++++---------- petitions/settings/base.py | 10 +++ 3 files changed, 124 insertions(+), 38 deletions(-) diff --git a/Pipfile b/Pipfile index 987633c..3b0e958 100644 --- a/Pipfile +++ b/Pipfile @@ -10,5 +10,6 @@ django = "~=2.1" black = "==18.9b0" dj-database-url = "*" psycopg2 = "*" +django-cas-ng = "*" [requires] diff --git a/Pipfile.lock b/Pipfile.lock index 39ac889..60f75f0 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "0fb89abc35fbcf26ea32dc29d3d2d4c59fbd555b8ae23cdd21be57fbff8af904" + "sha256": "9d477408017f929faadf03666e227c448f54feebe093b233eabbaf42bfa8828d" }, "pipfile-spec": 6, "requires": {}, @@ -23,10 +23,10 @@ }, "attrs": { "hashes": [ - "sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", - "sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb" + "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", + "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" ], - "version": "==18.2.0" + "version": "==19.1.0" }, "black": { "hashes": [ @@ -36,6 +36,20 @@ "index": "pypi", "version": "==18.9b0" }, + "certifi": { + "hashes": [ + "sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5", + "sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae" + ], + "version": "==2019.3.9" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, "click": { "hashes": [ "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", @@ -53,47 +67,80 @@ }, "django": { "hashes": [ - "sha256:275bec66fd2588dd517ada59b8bfb23d4a9abc5a362349139ddda3c7ff6f5ade", - "sha256:939652e9d34d7d53d74d5d8ef82a19e5f8bb2de75618f7e5360691b6e9667963" + "sha256:7c3543e4fb070d14e10926189a7fcf42ba919263b7473dceaefce34d54e8a119", + "sha256:a2814bffd1f007805b19194eb0b9a331933b82bd5da1c3ba3d7b7ba16e06dc4b" + ], + "index": "pypi", + "version": "==2.2" + }, + "django-cas-ng": { + "hashes": [ + "sha256:108e6a8bf578b3b817dfcfda25d11b9898856f3e1b82bf69150ffe5198455ba5", + "sha256:298b8b7d809b61f31caf188c3a4a568790f259cbac6e4f49ed4cb3ac4f8db9d2" ], "index": "pypi", - "version": "==2.1.7" + "version": "==3.6.0" + }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "lxml": { + "hashes": [ + "sha256:03984196d00670b2ab14ae0ea83d5cc0cfa4f5a42558afa9ab5fa745995328f5", + "sha256:0815b0c9f897468de6a386dc15917a0becf48cc92425613aa8bbfc7f0f82951f", + "sha256:175f3825f075cf02d15099eb52658457cf0ff103dcf11512b5d2583e1d40f58b", + "sha256:30e14c62d88d1e01a26936ecd1c6e784d4afc9aa002bba4321c5897937112616", + "sha256:3210da6f36cf4b835ff1be853962b22cc354d506f493b67a4303c88bbb40d57b", + "sha256:40f60819fbd5bad6e191ba1329bfafa09ab7f3f174b3d034d413ef5266963294", + "sha256:43b26a865a61549919f8a42e094dfdb62847113cf776d84bd6b60e4e3fc20ea3", + "sha256:4a03dd682f8e35a10234904e0b9508d705ff98cf962c5851ed052e9340df3d90", + "sha256:62f382cddf3d2e52cf266e161aa522d54fd624b8cc567bc18f573d9d50d40e8e", + "sha256:7b98f0325be8450da70aa4a796c4f06852949fe031878b4aa1d6c417a412f314", + "sha256:846a0739e595871041385d86d12af4b6999f921359b38affb99cdd6b54219a8f", + "sha256:a3080470559938a09a5d0ec558c005282e99ac77bf8211fb7b9a5c66390acd8d", + "sha256:ad841b78a476623955da270ab8d207c3c694aa5eba71f4792f65926dc46c6ee8", + "sha256:afdd75d9735e44c639ffd6258ce04a2de3b208f148072c02478162d0944d9da3", + "sha256:b4fbf9b552faff54742bcd0791ab1da5863363fb19047e68f6592be1ac2dab33", + "sha256:b90c4e32d6ec089d3fa3518436bdf5ce4d902a0787dbd9bb09f37afe8b994317", + "sha256:b91cfe4438c741aeff662d413fd2808ac901cc6229c838236840d11de4586d63", + "sha256:bdb0593a42070b0a5f138b79b872289ee73c8e25b3f0bea6564e795b55b6bcdd", + "sha256:c4e4bca2bb68ce22320297dfa1a7bf070a5b20bcbaec4ee023f83d2f6e76496f", + "sha256:cec4ab14af9eae8501be3266ff50c3c2aecc017ba1e86c160209bb4f0423df6a", + "sha256:e83b4b2bf029f5104bc1227dbb7bf5ace6fd8fabaebffcd4f8106fafc69fc45f", + "sha256:e995b3734a46d41ae60b6097f7c51ba9958648c6d1e0935b7e0ee446ee4abe22", + "sha256:f679d93dec7f7210575c85379a31322df4c46496f184ef650d3aba1484b38a2d", + "sha256:fd213bb5166e46974f113c8228daaef1732abc47cb561ce9c4c8eaed4bd3b09b", + "sha256:fdcb57b906dbc1f80666e6290e794ab8fb959a2e17aa5aee1758a85d1da4533f", + "sha256:ff424b01d090ffe1947ec7432b07f536912e0300458f9a7f48ea217dd8362b86" + ], + "version": "==4.3.3" }, "psycopg2": { "hashes": [ - "sha256:02445ebbb3a11a3fe8202c413d5e6faf38bb75b4e336203ee144ca2c46529f94", - "sha256:0e9873e60f98f0c52339abf8f0339d1e22bfe5aae0bcf7aabd40c055175035ec", - "sha256:1148a5eb29073280bf9057c7fc45468592c1bb75a28f6df1591adb93c8cb63d0", - "sha256:259a8324e109d4922b0fcd046e223e289830e2568d6f4132a3702439e5fd532b", - "sha256:28dffa9ed4595429e61bacac41d3f9671bb613d1442ff43bcbec63d4f73ed5e8", - "sha256:314a74302d4737a3865d40ea50e430ce1543c921ba10f39d562e807cfe2edf2a", - "sha256:36b60201b6d215d7658a71493fdf6bd5e60ad9a0cffed39906627ff9f4f3afd3", - "sha256:3f9d532bce54c4234161176ff3b8688ff337575ca441ea27597e112dfcd0ee0c", - "sha256:5d222983847b40af989ad96c07fc3f07e47925e463baa5de716be8f805b41d9b", - "sha256:6757a6d2fc58f7d8f5d471ad180a0bd7b4dd3c7d681f051504fbea7ae29c8d6f", - "sha256:6a0e0f1e74edb0ab57d89680e59e7bfefad2bfbdf7c80eb38304d897d43674bb", - "sha256:6ca703ccdf734e886a1cf53eb702261110f6a8b0ed74bcad15f1399f74d3f189", - "sha256:8513b953d8f443c446aa79a4cc8a898bd415fc5e29349054f03a7d696d495542", - "sha256:9262a5ce2038570cb81b4d6413720484cb1bc52c064b2f36228d735b1f98b794", - "sha256:97441f851d862a0c844d981cbee7ee62566c322ebb3d68f86d66aa99d483985b", - "sha256:a07feade155eb8e69b54dd6774cf6acf2d936660c61d8123b8b6b1f9247b67d6", - "sha256:a9b9c02c91b1e3ec1f1886b2d0a90a0ea07cc529cb7e6e472b556bc20ce658f3", - "sha256:ae88216f94728d691b945983140bf40d51a1ff6c7fe57def93949bf9339ed54a", - "sha256:b360ffd17659491f1a6ad7c928350e229c7b7bd83a2b922b6ee541245c7a776f", - "sha256:b4221957ceccf14b2abdabef42d806e791350be10e21b260d7c9ce49012cc19e", - "sha256:b90758e49d5e6b152a460d10b92f8a6ccf318fcc0ee814dcf53f3a6fc5328789", - "sha256:c669ea986190ed05fb289d0c100cc88064351f2b85177cbfd3564c4f4847d18c", - "sha256:d1b61999d15c79cf7f4f7cc9021477aef35277fc52452cf50fd13b713c84424d", - "sha256:de7bb043d1adaaf46e38d47e7a5f703bb3dab01376111e522b07d25e1a79c1e1", - "sha256:e393568e288d884b94d263f2669215197840d097c7e5b0acd1a51c1ea7d1aba8", - "sha256:ed7e0849337bd37d89f2c2b0216a0de863399ee5d363d31b1e5330a99044737b", - "sha256:f153f71c3164665d269a5d03c7fa76ba675c7a8de9dc09a4e2c2cdc9936a7b41", - "sha256:f1fb5a8427af099beb7f65093cbdb52e021b8e6dbdfaf020402a623f4181baf5", - "sha256:f36b333e9f86a2fba960c72b90c34be6ca71819e300f7b1fc3d2b0f0b2c546cd", - "sha256:f4526d078aedd5187d0508aa5f9a01eae6a48a470ed678406da94b4cd6524b7e" + "sha256:2433931723bf6be4bd342e003ffa9a1cef2cb4de7735d5b063fd554fd64a744c", + "sha256:2a0497c8ade1a5a0dc3d62b7f1a4fbcbccfa15d9ef69cce064119cd723566392", + "sha256:3ad3cf4732ff7d87dc12031836e5097fc42be767193771da90b8b5038cdca412", + "sha256:453c5bc0563c9b9601ef9243c095da9e327f24da6917b7c3ede8e0cd9dd9477d", + "sha256:49c5838d90e83217909db3789d30a105385b5e696ec5168cda645546c542f35a", + "sha256:6d849117337afd1aa0a74ab9a6c9d2160228d25d5babfa4d9a98bf4a4dad8062", + "sha256:8980dbabfb2ed0866b6bd5687d1407c3bccaac1f2f496f1206472108be69b92d", + "sha256:a286480430af972be9c30333c48883890dc8d87eab0d591e24975dcf99abff6c", + "sha256:bc7ec9ab1f33edd5db40edfb407aabdc92e573c4fcacd9093a9a6f3dd93c7af2", + "sha256:d303d9f88ec839a51b430bbec0f4a8314d0d2a53f760e67e95e25e39f6d6fb5f", + "sha256:e9836455931ac3d91b71312fa3bb2b9db8c42720a53b7de7db082406e4828585" ], "index": "pypi", - "version": "==2.7.7" + "version": "==2.8" + }, + "python-cas": { + "hashes": [ + "sha256:934af22469d87cff27cd22c8d94ef9265e587e5b83758fc95a91875df9574692" + ], + "version": "==1.4.0" }, "pytz": { "hashes": [ @@ -102,12 +149,40 @@ ], "version": "==2018.9" }, + "requests": { + "hashes": [ + "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", + "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" + ], + "version": "==2.21.0" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "sqlparse": { + "hashes": [ + "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", + "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" + ], + "version": "==0.3.0" + }, "toml": { "hashes": [ "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e" ], "version": "==0.10.0" + }, + "urllib3": { + "hashes": [ + "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", + "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" + ], + "version": "==1.24.1" } }, "develop": {} diff --git a/petitions/settings/base.py b/petitions/settings/base.py index 4d53680..286a111 100644 --- a/petitions/settings/base.py +++ b/petitions/settings/base.py @@ -35,7 +35,9 @@ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", + "django_cas_ng", "index", + ] MIDDLEWARE = [ @@ -46,8 +48,16 @@ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django_cas_ng.middleware.CASMiddleware", ] +AUTHENTICATION_BACKENDS = [ + 'django.contrib.auth.backends.ModelBackend', + 'petitions.backends.CASBackend', +] + +CAS_SERVER_URL = 'https://cas-auth.rpi.edu/cas/' +CAS_REDIRECT_URL = 'http://localhost:8000/' ROOT_URLCONF = "petitions.urls" TEMPLATES = [ From 84ea016dd88c9df41daacb1f818288dd78895a8a Mon Sep 17 00:00:00 2001 From: garoller Date: Fri, 5 Apr 2019 13:08:19 -0400 Subject: [PATCH 05/33] Run black --- petitions/settings/base.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/petitions/settings/base.py b/petitions/settings/base.py index 286a111..3abe833 100644 --- a/petitions/settings/base.py +++ b/petitions/settings/base.py @@ -37,7 +37,6 @@ "django.contrib.staticfiles", "django_cas_ng", "index", - ] MIDDLEWARE = [ @@ -52,12 +51,12 @@ ] AUTHENTICATION_BACKENDS = [ - 'django.contrib.auth.backends.ModelBackend', - 'petitions.backends.CASBackend', + "django.contrib.auth.backends.ModelBackend", + "petitions.backends.CASBackend", ] -CAS_SERVER_URL = 'https://cas-auth.rpi.edu/cas/' -CAS_REDIRECT_URL = 'http://localhost:8000/' +CAS_SERVER_URL = "https://cas-auth.rpi.edu/cas/" +CAS_REDIRECT_URL = "http://localhost:8000/" ROOT_URLCONF = "petitions.urls" TEMPLATES = [ From 8eb37f1d98e4a5b006b8953a8ae90a740b68ca1c Mon Sep 17 00:00:00 2001 From: garoller Date: Fri, 5 Apr 2019 13:10:11 -0400 Subject: [PATCH 06/33] Switch to use django built in user model --- index/migrations/0006_auto_20190402_1928.py | 34 ++++++++++++++++++ index/models.py | 39 ++++++--------------- 2 files changed, 45 insertions(+), 28 deletions(-) create mode 100644 index/migrations/0006_auto_20190402_1928.py diff --git a/index/migrations/0006_auto_20190402_1928.py b/index/migrations/0006_auto_20190402_1928.py new file mode 100644 index 0000000..73d244b --- /dev/null +++ b/index/migrations/0006_auto_20190402_1928.py @@ -0,0 +1,34 @@ +# Generated by Django 2.2 on 2019-04-02 19:28 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [("index", "0005_auto_20190303_0230")] + + operations = [ + migrations.AlterField( + model_name="petition", + name="author", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="petitions", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AlterField( + model_name="signature", + name="signer", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="signatures", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.DeleteModel(name="User"), + ] diff --git a/index/models.py b/index/models.py index e8c2475..22cbc85 100644 --- a/index/models.py +++ b/index/models.py @@ -1,6 +1,7 @@ from django.db import models from django.utils import timezone from django.urls import reverse +from django.contrib.auth.models import User # Creates a tag, there can be at most three in a single petition class Tag(models.Model): @@ -13,34 +14,6 @@ def __unicode__(self): def __str__(self): return self.label - -# Creates a user based on their name, RCS ID and admin status -class User(models.Model): - rcs_id = models.CharField(max_length=10, primary_key=True) # RCS ID - name = models.CharField(max_length=50) # The author name - admin = models.BooleanField(default=False) # Is admin? - # Is the person banned?-- not very likely - banned = models.BooleanField(default=False) - initials = models.CharField(max_length=2) # Their initials - union_member = models.BooleanField(default=False) # Is member of the union? - - # Returns their name - def __unicode__(self): - return self.rcs_id - - # Returns the initials of the User using the RCS ID, first strips - # it of the digits at the end and then - def set_initials(self): - full_name = self.rcs_id - name_modified = "".join([i for i in full_name if not i.isdigit()]) - self.initials = name_modified[-1] + name_modified[0] - - # Changes the bool value that dictates whether or not a character - # is a admin - def set_admin(self, bool_val): - self.admin = bool_val - - # Logs a signature, there can be many in a single petition class Signature(models.Model): # The person trying to sign the petition @@ -53,6 +26,11 @@ class Signature(models.Model): def __unicode__(self): return self.signer + def get_initials(self): + full_name = self.signer.get_username() + name_modified = "".join([i for i in full_name if not i.isdigit()]) + return name_modified[-1] + name_modified[0] + # Creates a response based on whether the senate is investigating the topic of the Petition class Response(models.Model): @@ -191,3 +169,8 @@ def check_tags(self): def get_url(self): return reverse("petition-detail", args=[str(self.ID)]) + + # register = template.Library() + # @register.simple_tag + # def get_sign_url(self, user): + # return reverse("sign", args=[str(self.ID), str(user.username)]) From 6be1fef12c93e85f892f909df99929f24188a871 Mon Sep 17 00:00:00 2001 From: garoller Date: Fri, 5 Apr 2019 13:12:04 -0400 Subject: [PATCH 07/33] Add sign, login, and logout --- index/urls.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index/urls.py b/index/urls.py index addf613..8605011 100644 --- a/index/urls.py +++ b/index/urls.py @@ -1,4 +1,5 @@ from django.urls import path +import django_cas_ng.views from . import views urlpatterns = [ @@ -6,4 +7,7 @@ path("create/", views.create, name="create"), path("all/", views.all, name="all"), path("petition/", views.petition_detail, name="petition-detail"), + path("petition//sign/", views.add_signature, name="sign"), + path("login/", django_cas_ng.views.LoginView.as_view(), name="cas_ng_login"), + path("logout/", django_cas_ng.views.LogoutView.as_view(), name="cas_ng_logout"), ] From c6b30b0c1139a839af0af913e52ef15cf5bcb545 Mon Sep 17 00:00:00 2001 From: garoller Date: Fri, 5 Apr 2019 13:13:01 -0400 Subject: [PATCH 08/33] Add signature view --- index/views.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/index/views.py b/index/views.py index 3aa69ad..086d6fa 100644 --- a/index/views.py +++ b/index/views.py @@ -1,8 +1,8 @@ -from django.shortcuts import render +from django.shortcuts import render, redirect from django.views import generic from django.utils import timezone from .forms import CreatePetitionForm -from .models import Petition, Tag +from .models import Petition, Tag, User, Signature def index(request): @@ -30,23 +30,28 @@ def petition_detail(request, pk): status = "Goal met" expiration_date = petition.created_date + timezone.timedelta(days=365) - + progress_percent = int((petition.signatures.count() / petition.expected_sig) * 100) context = { "petition": petition, "signatures": signatures, "status": status, "date": expiration_date, + "progress_percent": progress_percent, } return render(request, "detail.html", context=context) -# def add_signature(request, pk, user_pk): -# petition = Petition.objects.get(pk=pk) -# user = User.objects.get(pk=user_pk) -# new_signature = Signature.create(user) -# new_signature.save() +def add_signature(request, pk, pk_user): + + petition = Petition.objects.get(pk=pk) + + if petition.signatures.filter(pk=pk_user).exists(): + return redirect("/petition/" + str(pk)) -# petition.signatures.add(new_signature) -# petition.save() + user = User.objects.get(pk=pk_user) + new_signature = Signature(signer=user) + new_signature.save() + petition.signatures.add(new_signature) + petition.save() -# return petition_detail() + return redirect("/petition/" + str(pk)) From 282d582b58d17ae58c3c26a2ff4e94c4a4f6a9c9 Mon Sep 17 00:00:00 2001 From: garoller Date: Fri, 5 Apr 2019 13:14:05 -0400 Subject: [PATCH 09/33] Use template tag for signing --- index/templatetags/__init__.py | 0 index/templatetags/sign_tags.py | 9 +++++++++ 2 files changed, 9 insertions(+) create mode 100644 index/templatetags/__init__.py create mode 100644 index/templatetags/sign_tags.py diff --git a/index/templatetags/__init__.py b/index/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/index/templatetags/sign_tags.py b/index/templatetags/sign_tags.py new file mode 100644 index 0000000..85bd78f --- /dev/null +++ b/index/templatetags/sign_tags.py @@ -0,0 +1,9 @@ +from django import template +from django.urls import reverse + +register = template.Library() + + +@register.simple_tag +def get_sign_url(petition, user): + return reverse("sign", kwargs={"pk": str(petition.ID), "pk_user": str(user.pk)}) From 55e876d7ce3d32faecb19214b8b27ddb9efa422c Mon Sep 17 00:00:00 2001 From: garoller Date: Fri, 5 Apr 2019 13:15:03 -0400 Subject: [PATCH 10/33] Use custom CAS backend to check RPI student status --- petitions/backends.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 petitions/backends.py diff --git a/petitions/backends.py b/petitions/backends.py new file mode 100644 index 0000000..5b0fa58 --- /dev/null +++ b/petitions/backends.py @@ -0,0 +1,7 @@ +from django_cas_ng.backends import CASBackend + + +class StudentCASBackend(CASBackend): + def user_can_authenticate(self, user): + # TODO: add WTG identity to check if user is a student + return True From 3720a9b0de517b62bac1eb7a1eff1d34ba58f944 Mon Sep 17 00:00:00 2001 From: garoller Date: Fri, 5 Apr 2019 13:15:43 -0400 Subject: [PATCH 11/33] Updated front end --- index/static/petition/style.css | 35 +++++++++++++++++++++++++++++---- index/templates/base.html | 10 ++++++++-- index/templates/detail.html | 20 +++++++++---------- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/index/static/petition/style.css b/index/static/petition/style.css index ee1c24f..eaf06e6 100644 --- a/index/static/petition/style.css +++ b/index/static/petition/style.css @@ -12,8 +12,12 @@ body { width: 100%; } -.nav-link { - color: #000000; +.nav-link, .btn-link { + color: gray; +} + +.nav-item { + padding-left: 10px; } .wtg-logo { @@ -91,7 +95,7 @@ body { color: #505050; } -.link, .link:hover { +.link, .link:hover, .btn-link:hover { color: gray; } @@ -126,4 +130,27 @@ body { #sign-btn { background-color: #ed1c24; color: white; -} \ No newline at end of file +} + +#sign-btn:hover { + background-color: #ebebeb; + border-color: #ed1c24; + color: #ed1c24; +} + +.flex-sig-container { + display: flex; + flex-flow: row wrap; + list-style-type: none; + padding-left: 0px; +} + +.flex-sig { + padding: 5px; + margin-top: 10px; + text-align: center; +} + +.progress-bar { + background-color: #ed1c24 !important; +} diff --git a/index/templates/base.html b/index/templates/base.html index 31172ca..298973e 100644 --- a/index/templates/base.html +++ b/index/templates/base.html @@ -33,9 +33,15 @@ + + {% if user.is_authenticated %} + + {% else %} + + {% endif %} + +
diff --git a/index/templates/detail.html b/index/templates/detail.html index 81dc510..1261f2f 100644 --- a/index/templates/detail.html +++ b/index/templates/detail.html @@ -17,24 +17,26 @@
Description
Signed by
- {% for signature in signatures %} -

signature.signer.initials

- {% empty %} -

No signatures yet

- {% endfor %} +
    + {% for signature in signatures %} +
  • {{ signature.get_initials }}
  • + {% empty %} +
  • No signatures yet
  • + {% endfor %} +
Take action
- +
{{signatures.count}} / {{petition.expected_sig}} Signatures
-
+
@@ -48,9 +50,5 @@
Expires
{{ date|date:'M d, Y' }}
- - - - {% endblock %} \ No newline at end of file From a1441376be3b4f977298b85ad3dfefc510e08307 Mon Sep 17 00:00:00 2001 From: garoller Date: Mon, 8 Apr 2019 22:30:25 -0400 Subject: [PATCH 12/33] Fix padding --- index/static/petition/style.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index/static/petition/style.css b/index/static/petition/style.css index eaf06e6..76e5d71 100644 --- a/index/static/petition/style.css +++ b/index/static/petition/style.css @@ -146,7 +146,8 @@ body { } .flex-sig { - padding: 5px; + padding-bottom: 10px; + padding-right: 10px; margin-top: 10px; text-align: center; } From db7060e863c71a237e56edb030d876e2bda52084 Mon Sep 17 00:00:00 2001 From: garoller Date: Mon, 8 Apr 2019 22:31:19 -0400 Subject: [PATCH 13/33] Fix custom CAS backend --- petitions/backends.py | 17 ++++++++++++++++- petitions/settings/base.py | 4 ++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/petitions/backends.py b/petitions/backends.py index 5b0fa58..64b6705 100644 --- a/petitions/backends.py +++ b/petitions/backends.py @@ -1,7 +1,22 @@ from django_cas_ng.backends import CASBackend +from django.conf import settings +import requests +import os class StudentCASBackend(CASBackend): def user_can_authenticate(self, user): - # TODO: add WTG identity to check if user is a student + url = ( + "https://webtech.union.rpi.edu/services/identity/valid/" + + str(user.username).lower() + ) + key = str(os.environ.get("IDENTITY_KEY")) + r = requests.get(url, headers={"Authorization": "Token " + key}) + error = r.json()["error"] + if error: + return False + student = r.json()["user_type"] == "Student" + if not student: + return False + return True diff --git a/petitions/settings/base.py b/petitions/settings/base.py index 3abe833..2a40dcd 100644 --- a/petitions/settings/base.py +++ b/petitions/settings/base.py @@ -52,11 +52,11 @@ AUTHENTICATION_BACKENDS = [ "django.contrib.auth.backends.ModelBackend", - "petitions.backends.CASBackend", + "petitions.backends.StudentCASBackend", ] CAS_SERVER_URL = "https://cas-auth.rpi.edu/cas/" -CAS_REDIRECT_URL = "http://localhost:8000/" + ROOT_URLCONF = "petitions.urls" TEMPLATES = [ From 7bd86b4699eea3214ce6b29b38a6a99e89b444ab Mon Sep 17 00:00:00 2001 From: garoller Date: Mon, 8 Apr 2019 22:35:35 -0400 Subject: [PATCH 14/33] Check if user already signed and is logged in --- index/templates/detail.html | 15 ++++++++++++++- index/templatetags/sign_tags.py | 8 ++++++++ index/views.py | 6 +----- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/index/templates/detail.html b/index/templates/detail.html index 1261f2f..76a414f 100644 --- a/index/templates/detail.html +++ b/index/templates/detail.html @@ -30,7 +30,20 @@
Signed by
Take action
- + + {% if user.is_authenticated %} + + {% load sign_tags %} + {% user_signed petition user as signed %} + {% if signed %} + + {% else %} + + {% endif %} + + {% else %} + + {% endif %}
diff --git a/index/templatetags/sign_tags.py b/index/templatetags/sign_tags.py index 85bd78f..e51e040 100644 --- a/index/templatetags/sign_tags.py +++ b/index/templatetags/sign_tags.py @@ -7,3 +7,11 @@ @register.simple_tag def get_sign_url(petition, user): return reverse("sign", kwargs={"pk": str(petition.ID), "pk_user": str(user.pk)}) + + +@register.simple_tag +def user_signed(petition, user): + if petition.signatures.filter(signer=user).exists(): + return True + + return False diff --git a/index/views.py b/index/views.py index 086d6fa..3d27660 100644 --- a/index/views.py +++ b/index/views.py @@ -42,13 +42,9 @@ def petition_detail(request, pk): def add_signature(request, pk, pk_user): - petition = Petition.objects.get(pk=pk) - - if petition.signatures.filter(pk=pk_user).exists(): - return redirect("/petition/" + str(pk)) - user = User.objects.get(pk=pk_user) + new_signature = Signature(signer=user) new_signature.save() petition.signatures.add(new_signature) From bca59c5af1832152c68c567ec3bc329760b591fc Mon Sep 17 00:00:00 2001 From: garoller Date: Mon, 8 Apr 2019 23:11:23 -0400 Subject: [PATCH 15/33] Remove user test --- index/tests.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/index/tests.py b/index/tests.py index 8dbfeae..2e23740 100644 --- a/index/tests.py +++ b/index/tests.py @@ -1,5 +1,5 @@ import unittest -from .models import Petition, Tag, User, Response, Signature +from index.models import Petition, Tag, Response, Signature class PetitionModelTestCase(unittest.TestCase): @@ -14,10 +14,3 @@ def test_title(self): # def test_check_enough_signatures(self): # petition = Petition(title="Save Greek Life") # self.assertFalse(petition.check_enough_sigs()) - - -class UserModelTestCase(unittest.TestCase): - def test_user_initials(self): - user = User(rcs_id="rolleg", name="Grace Roller") - user.set_initials() - self.assertEqual("gr", user.initials) From 6ecab79ca09594f6a36347ce4395950f91431ebc Mon Sep 17 00:00:00 2001 From: garoller Date: Mon, 8 Apr 2019 23:14:10 -0400 Subject: [PATCH 16/33] Run black --- index/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/index/models.py b/index/models.py index 22cbc85..4560004 100644 --- a/index/models.py +++ b/index/models.py @@ -14,6 +14,7 @@ def __unicode__(self): def __str__(self): return self.label + # Logs a signature, there can be many in a single petition class Signature(models.Model): # The person trying to sign the petition From 8ea8ec4f69028958472848f70257013f696366fc Mon Sep 17 00:00:00 2001 From: garoller Date: Mon, 8 Apr 2019 23:36:54 -0400 Subject: [PATCH 17/33] Run index tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e01d437..d2d455b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,4 +25,4 @@ before_script: - pipenv run black . --check script: - - pipenv run python manage.py test + - pipenv run python manage.py test index From bf11dc86897220e00be73281ba6dcc13a8a94676 Mon Sep 17 00:00:00 2001 From: garoller Date: Mon, 8 Apr 2019 23:37:34 -0400 Subject: [PATCH 18/33] Change test package --- index/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index/tests.py b/index/tests.py index 2e23740..a23b384 100644 --- a/index/tests.py +++ b/index/tests.py @@ -1,8 +1,8 @@ -import unittest +from django.test import TestCase from index.models import Petition, Tag, Response, Signature -class PetitionModelTestCase(unittest.TestCase): +class PetitionModelTestCase(TestCase): def test_title(self): petition = Petition(title="Save Greek Life") self.assertEqual("Save Greek Life", petition.title) From ce5fc50bb128d16b1a383a6ea6d43b45cc0cd292 Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 9 Apr 2019 12:05:44 -0400 Subject: [PATCH 19/33] Switch to xenial python 3.6 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d2d455b..7d6724a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: python matrix: include: - python: "3.6" - dist: trusty + dist: xenial sudo: true - python: "3.7" dist: xenial From 8db7e8511eaae9be2c67c36c21a9efdaa224de12 Mon Sep 17 00:00:00 2001 From: garoller Date: Wed, 10 Apr 2019 18:36:11 -0400 Subject: [PATCH 20/33] Don't bold the petition author --- index/static/petition/style.css | 3 --- 1 file changed, 3 deletions(-) diff --git a/index/static/petition/style.css b/index/static/petition/style.css index 76e5d71..50294ec 100644 --- a/index/static/petition/style.css +++ b/index/static/petition/style.css @@ -60,15 +60,12 @@ body { } .detail { - /* text-align: center; */ - /* margin-left: 40px; */ margin-top: 50px; padding-left: 20px; } .parent { display: flex; - /* align-items: center; */ } .left { From 836c07b5c5d040202d8439fd111f3a9529bd5d7d Mon Sep 17 00:00:00 2001 From: garoller Date: Wed, 10 Apr 2019 18:36:35 -0400 Subject: [PATCH 21/33] Fix comments --- index/models.py | 55 +++++++++++++++++++------------------------------ 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/index/models.py b/index/models.py index 4560004..f2c1e8d 100644 --- a/index/models.py +++ b/index/models.py @@ -106,72 +106,59 @@ class Petition(models.Model): archived = models.BooleanField(default=False) hidden = models.BooleanField(default=False) - created_date = models.DateTimeField( - db_index=True, default=timezone.now - ) # Files the date created - expected_sig = models.IntegerField( - 300 - ) # The expected signature to move to the next step - + # Files the date created + created_date = models.DateTimeField(db_index=True, default=timezone.now) + # The expected signature to move to the next step + expected_sig = models.IntegerField(300) + # The author of the petition author = models.ForeignKey( User, on_delete=models.CASCADE, related_name="petitions", blank=True, null=True - ) # The author of the petition - tags = models.ManyToManyField( - Tag, related_name="petitions", blank=True - ) # The tags, probably a max of 3 - signatures = models.ManyToManyField( - Signature, related_name="petitions", blank=True - ) # The signature - + ) + # The tags, probably a max of 3 + tags = models.ManyToManyField(Tag, related_name="petitions", blank=True) + # The signature + signatures = models.ManyToManyField(Signature, related_name="petitions", blank=True) + # If the senate has responded , their answer senate_response = models.ForeignKey( Response, on_delete=models.CASCADE, related_name="petitions", blank=True, null=True, - ) # If the senate has responded , their answer + ) # Returns title when asked for the item def __unicode__(self): return self.title - # Sets the hidden variable as true if we don't want it to - # Be displayed in the main site - + # Sets the hidden variable as true if we don't want it to + # Be displayed in the main site def set_hidden(self, bool_val): self.hidden = bool_val - # If the petition isn't active, we can set the archived variable as true - + # If the petition isn't active, we can set the archived variable as true def set_archived(self, bool_val): self.archived = bool_val - # Adds a description to the basic petitions model, with a max length - # of 4000 words - + # Adds a description to the basic petitions model, with a max length + # of 4000 words def add_description(self, descript): self.description = descript return True - # Returns true if we have enough signatures on the petition + # Returns true if we have enough signatures on the petition def check_enough_sigs(self): if self.signatures.count() >= self.expected_sig: return True return False - # Makes sure the we have less than three tags in the model + # Makes sure the we have less than three tags in the model def check_tags(self): if self.tags.count() > 3: return False return True - # Add tag to a petition, there can be at most three in a single petition - # def add_tag (self): - + # Add tag to a petition, there can be at most three in a single petition + # def add_tag (self): def get_url(self): return reverse("petition-detail", args=[str(self.ID)]) - - # register = template.Library() - # @register.simple_tag - # def get_sign_url(self, user): - # return reverse("sign", args=[str(self.ID), str(user.username)]) From dbc4f3e33e5288e10ff685c04acd0b3004926e34 Mon Sep 17 00:00:00 2001 From: garoller Date: Wed, 10 Apr 2019 18:37:45 -0400 Subject: [PATCH 22/33] Use a template tag to sign --- index/templates/detail.html | 6 +++--- index/templatetags/sign_tags.py | 15 +++++++++++++-- index/urls.py | 1 - index/views.py | 12 ------------ 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/index/templates/detail.html b/index/templates/detail.html index 76a414f..f9aeb5a 100644 --- a/index/templates/detail.html +++ b/index/templates/detail.html @@ -5,7 +5,7 @@

{{ petition.title }}

-
Created by {{ petition.author.rcs_id }}
+
Created by {{ petition.author.rcs_id }}
@@ -33,12 +33,12 @@
Take action
{% if user.is_authenticated %} - {% load sign_tags %} + {% load user_signed from sign_tags %} {% user_signed petition user as signed %} {% if signed %} {% else %} - + {% endif %} {% else %} diff --git a/index/templatetags/sign_tags.py b/index/templatetags/sign_tags.py index e51e040..b9bcdd2 100644 --- a/index/templatetags/sign_tags.py +++ b/index/templatetags/sign_tags.py @@ -1,12 +1,23 @@ from django import template from django.urls import reverse +from django.shortcuts import redirect +from index.models import Signature +from index import urls register = template.Library() @register.simple_tag -def get_sign_url(petition, user): - return reverse("sign", kwargs={"pk": str(petition.ID), "pk_user": str(user.pk)}) +def add_signature(petition, user): + # petition = Petition.objects.get(pk=pk) + # user = User.objects.get(pk=pk_user) + + new_signature = Signature(signer=user) + new_signature.save() + petition.signatures.add(new_signature) + petition.save() + + return reverse("petition-detail", kwargs={"pk": str(petition.pk)}) @register.simple_tag diff --git a/index/urls.py b/index/urls.py index 8605011..946db78 100644 --- a/index/urls.py +++ b/index/urls.py @@ -7,7 +7,6 @@ path("create/", views.create, name="create"), path("all/", views.all, name="all"), path("petition/", views.petition_detail, name="petition-detail"), - path("petition//sign/", views.add_signature, name="sign"), path("login/", django_cas_ng.views.LoginView.as_view(), name="cas_ng_login"), path("logout/", django_cas_ng.views.LogoutView.as_view(), name="cas_ng_logout"), ] diff --git a/index/views.py b/index/views.py index 3d27660..bf0770d 100644 --- a/index/views.py +++ b/index/views.py @@ -39,15 +39,3 @@ def petition_detail(request, pk): "progress_percent": progress_percent, } return render(request, "detail.html", context=context) - - -def add_signature(request, pk, pk_user): - petition = Petition.objects.get(pk=pk) - user = User.objects.get(pk=pk_user) - - new_signature = Signature(signer=user) - new_signature.save() - petition.signatures.add(new_signature) - petition.save() - - return redirect("/petition/" + str(pk)) From 7c7bb3ad966c9aaf4d49b994143e5cbc91d687f8 Mon Sep 17 00:00:00 2001 From: garoller Date: Thu, 11 Apr 2019 09:06:57 -0400 Subject: [PATCH 23/33] Use a form to sign --- index/forms.py | 5 +++++ index/templates/detail.html | 26 +++++++++++++++----------- index/templatetags/sign_tags.py | 17 ----------------- index/urls.py | 1 + index/views.py | 26 +++++++++++++++++++++++++- 5 files changed, 46 insertions(+), 29 deletions(-) diff --git a/index/forms.py b/index/forms.py index e53f170..5353199 100644 --- a/index/forms.py +++ b/index/forms.py @@ -11,3 +11,8 @@ class CreatePetitionForm(forms.ModelForm): class Meta: model = Petition fields = ["title", "description", "tags"] + + +class SignPetitionForm(forms.Form): + sign_btn = forms.CharField() + pk = forms.IntegerField() diff --git a/index/templates/detail.html b/index/templates/detail.html index f9aeb5a..df95982 100644 --- a/index/templates/detail.html +++ b/index/templates/detail.html @@ -31,19 +31,23 @@
Signed by
Take action
- {% if user.is_authenticated %} - - {% load user_signed from sign_tags %} - {% user_signed petition user as signed %} - {% if signed %} - +
{% csrf_token %} + {% if user.is_authenticated %} + + {% load user_signed from sign_tags %} + {% user_signed petition user as signed %} + {% if signed %} + + {% else %} + + + + {% endif %} + {% else %} - + {% endif %} - - {% else %} - - {% endif %} +
diff --git a/index/templatetags/sign_tags.py b/index/templatetags/sign_tags.py index b9bcdd2..04826a3 100644 --- a/index/templatetags/sign_tags.py +++ b/index/templatetags/sign_tags.py @@ -1,25 +1,8 @@ from django import template -from django.urls import reverse -from django.shortcuts import redirect -from index.models import Signature -from index import urls register = template.Library() -@register.simple_tag -def add_signature(petition, user): - # petition = Petition.objects.get(pk=pk) - # user = User.objects.get(pk=pk_user) - - new_signature = Signature(signer=user) - new_signature.save() - petition.signatures.add(new_signature) - petition.save() - - return reverse("petition-detail", kwargs={"pk": str(petition.pk)}) - - @register.simple_tag def user_signed(petition, user): if petition.signatures.filter(signer=user).exists(): diff --git a/index/urls.py b/index/urls.py index 946db78..46aaea6 100644 --- a/index/urls.py +++ b/index/urls.py @@ -7,6 +7,7 @@ path("create/", views.create, name="create"), path("all/", views.all, name="all"), path("petition/", views.petition_detail, name="petition-detail"), + path("petition/sign", views.sign, name="sign"), path("login/", django_cas_ng.views.LoginView.as_view(), name="cas_ng_login"), path("logout/", django_cas_ng.views.LogoutView.as_view(), name="cas_ng_logout"), ] diff --git a/index/views.py b/index/views.py index bf0770d..127c434 100644 --- a/index/views.py +++ b/index/views.py @@ -1,7 +1,13 @@ from django.shortcuts import render, redirect from django.views import generic from django.utils import timezone -from .forms import CreatePetitionForm +from django.http import ( + HttpResponse, + HttpResponseRedirect, + HttpResponseBadRequest, + HttpResponseNotAllowed, +) +from .forms import CreatePetitionForm, SignPetitionForm from .models import Petition, Tag, User, Signature @@ -39,3 +45,21 @@ def petition_detail(request, pk): "progress_percent": progress_percent, } return render(request, "detail.html", context=context) + + +def sign(request): + if request.method != "POST": + return HttpResponseNotAllowed(["POST"]) + + form = SignPetitionForm(request.POST) + + if form.is_valid(): + pk = form.cleaned_data["pk"] + petition = Petition.objects.get(pk=pk) + new_signature = Signature(signer=request.user) + new_signature.save() + petition.signatures.add(new_signature) + petition.save() + return HttpResponseRedirect("/petition/" + str(pk)) + + return HttpResponseBadRequest() From ce98170aaae2cd1660ba33f81a8dde87d1d7cd83 Mon Sep 17 00:00:00 2001 From: garoller Date: Thu, 11 Apr 2019 09:14:07 -0400 Subject: [PATCH 24/33] Update dependencies --- Pipfile.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 60f75f0..f912052 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -121,20 +121,20 @@ }, "psycopg2": { "hashes": [ - "sha256:2433931723bf6be4bd342e003ffa9a1cef2cb4de7735d5b063fd554fd64a744c", - "sha256:2a0497c8ade1a5a0dc3d62b7f1a4fbcbccfa15d9ef69cce064119cd723566392", - "sha256:3ad3cf4732ff7d87dc12031836e5097fc42be767193771da90b8b5038cdca412", - "sha256:453c5bc0563c9b9601ef9243c095da9e327f24da6917b7c3ede8e0cd9dd9477d", - "sha256:49c5838d90e83217909db3789d30a105385b5e696ec5168cda645546c542f35a", - "sha256:6d849117337afd1aa0a74ab9a6c9d2160228d25d5babfa4d9a98bf4a4dad8062", - "sha256:8980dbabfb2ed0866b6bd5687d1407c3bccaac1f2f496f1206472108be69b92d", - "sha256:a286480430af972be9c30333c48883890dc8d87eab0d591e24975dcf99abff6c", - "sha256:bc7ec9ab1f33edd5db40edfb407aabdc92e573c4fcacd9093a9a6f3dd93c7af2", - "sha256:d303d9f88ec839a51b430bbec0f4a8314d0d2a53f760e67e95e25e39f6d6fb5f", - "sha256:e9836455931ac3d91b71312fa3bb2b9db8c42720a53b7de7db082406e4828585" + "sha256:3648afc2b4828a6e00d516d2d09a260edd2c1e3de1e0d41d99c5ab004a73d180", + "sha256:5329b4530e31f58e0eafc55e26bbef684509bcc3be41604e45c0b98c297dc722", + "sha256:7c1ae1669d11105a002f804bebd7432f8dc7473459aa405164c6b44a922decd5", + "sha256:8af13498e32a00d0a66e43b7491c15231b27ab964ee4d2277a4a2dbadfb2c482", + "sha256:9d5489867bd5f6d6c6191a4debd8de9a5c03a9608cce3f4d7133e29e6bd4ec27", + "sha256:a17bfc9faffcca0ad9360c1ad97ab61ede583aa954715e8e436ffd80046661ff", + "sha256:b4a475ce87eabc0607e068a3c704d0aa0820237ed78d493b8e2d880eb73cd7fe", + "sha256:c49d66e97affdc80d084b3b363f09f17db621418f0b8e0524b06c54959e2094d", + "sha256:d13fbc3d533656cfdf094e13c1b0f40917b72813755ba780971ba0ce04280ac4", + "sha256:e1e4fe6e8ab9f9c7d28514d007f623999d2dd6b5b81069dd4f9d30dbdd6f7069", + "sha256:e67d60cb1a32f5fd8fcea935cf9efb1d1c26f96203b0ca2ae98c4c40ef8d8eac" ], "index": "pypi", - "version": "==2.8" + "version": "==2.8.1" }, "python-cas": { "hashes": [ @@ -144,10 +144,10 @@ }, "pytz": { "hashes": [ - "sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9", - "sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c" + "sha256:303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", + "sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141" ], - "version": "==2018.9" + "version": "==2019.1" }, "requests": { "hashes": [ From 21c9d4317929179fc1ccd70e218407f79d7f3347 Mon Sep 17 00:00:00 2001 From: garoller Date: Thu, 11 Apr 2019 09:20:38 -0400 Subject: [PATCH 25/33] Add pipenv sync instructions --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a7754b..f1db420 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,9 @@ Check the [Wiki](https://github.com/wtg/petitions-rewrite/wiki) for Django refer pipenv install --python ``` -5. Activate the virtual environment ```pipenv shell``` +5. Activate the virtual environment ```pipenv shell```. + + Then run ```pipenv sync``` to install all necessary dependencies. 6. Set a secret key environment variable ``` From 08876f9d1fa4cf5572fb8ba27024e5aaa2621485 Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 16 Apr 2019 14:28:26 -0400 Subject: [PATCH 26/33] Store users on petitions through signatures --- index/migrations/0001_initial.py | 158 ++++++-------------- index/migrations/0002_auto_20190215_0130.py | 28 ---- index/migrations/0003_auto_20190215_0136.py | 68 --------- index/migrations/0004_auto_20190215_0140.py | 58 ------- index/migrations/0005_auto_20190303_0230.py | 31 ---- index/migrations/0006_auto_20190402_1928.py | 34 ----- index/models.py | 40 +++-- 7 files changed, 60 insertions(+), 357 deletions(-) delete mode 100644 index/migrations/0002_auto_20190215_0130.py delete mode 100644 index/migrations/0003_auto_20190215_0136.py delete mode 100644 index/migrations/0004_auto_20190215_0140.py delete mode 100644 index/migrations/0005_auto_20190303_0230.py delete mode 100644 index/migrations/0006_auto_20190402_1928.py diff --git a/index/migrations/0001_initial.py b/index/migrations/0001_initial.py index 44133c4..59bcfb7 100644 --- a/index/migrations/0001_initial.py +++ b/index/migrations/0001_initial.py @@ -1,149 +1,77 @@ -# Generated by Django 2.1.1 on 2019-02-15 01:22 +# Generated by Django 2.2 on 2019-04-12 12:02 -import datetime +from django.conf import settings from django.db import migrations, models import django.db.models.deletion -from django.utils.timezone import utc +import django.utils.timezone class Migration(migrations.Migration): initial = True - dependencies = [] + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] operations = [ migrations.CreateModel( - name="Petition", - fields=[ - ("title", models.CharField(max_length=200)), - ("description", models.CharField(max_length=4000)), - ( - "ID", - models.IntegerField( - primary_key=True, serialize=False, verbose_name=999999 - ), - ), - ("archived", models.BooleanField(default=False)), - ("hidden", models.BooleanField(default=False)), - ( - "created_date", - models.DateTimeField( - db_index=True, - default=datetime.datetime( - 2019, 2, 15, 1, 22, 11, 359671, tzinfo=utc - ), - ), - ), - ("expected_sig", models.IntegerField(verbose_name=300)), - ], - ), - migrations.CreateModel( - name="Response", + name='Petition', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("senator_investigation", models.BooleanField(default=False)), - ("committee_formed", models.BooleanField(default=False)), - ("vote_resolution", models.BooleanField(default=False)), - ("vote_referendum", models.BooleanField(default=False)), - ("refer_to_other", models.BooleanField(default=False)), - ("investigation_info", models.CharField(max_length=1000)), - ("committee_info", models.CharField(max_length=1000)), - ("resolution_info", models.CharField(max_length=1000)), - ("referendum_info", models.CharField(max_length=1000)), - ("refer_other_info", models.CharField(max_length=1000)), + ('title', models.CharField(max_length=200)), + ('description', models.CharField(max_length=4000)), + ('ID', models.IntegerField(primary_key=True, serialize=False)), + ('archived', models.BooleanField(default=False)), + ('hidden', models.BooleanField(default=False)), + ('created_date', models.DateTimeField(db_index=True, default=django.utils.timezone.now)), + ('expected_sig', models.IntegerField(verbose_name=300)), + ('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='petition_author', to=settings.AUTH_USER_MODEL)), ], ), migrations.CreateModel( - name="Signature", + name='Response', fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ( - "signed_date", - models.DateTimeField( - default=datetime.datetime( - 2019, 2, 15, 1, 22, 11, 358683, tzinfo=utc - ) - ), - ), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('senator_investigation', models.BooleanField(default=False)), + ('committee_formed', models.BooleanField(default=False)), + ('vote_resolution', models.BooleanField(default=False)), + ('vote_referendum', models.BooleanField(default=False)), + ('refer_to_other', models.BooleanField(default=False)), + ('investigation_info', models.CharField(max_length=1000)), + ('committee_info', models.CharField(max_length=1000)), + ('resolution_info', models.CharField(max_length=1000)), + ('referendum_info', models.CharField(max_length=1000)), + ('refer_other_info', models.CharField(max_length=1000)), ], ), migrations.CreateModel( - name="Tag", + name='Tag', fields=[ - ( - "label", - models.CharField(max_length=15, primary_key=True, serialize=False), - ) + ('label', models.CharField(max_length=15, primary_key=True, serialize=False)), ], ), migrations.CreateModel( - name="User", + name='Signature', fields=[ - ( - "rcs_id", - models.CharField(max_length=10, primary_key=True, serialize=False), - ), - ("name", models.CharField(max_length=50)), - ("admin", models.BooleanField(default=False)), - ("banned", models.BooleanField(default=False)), - ("initials", models.CharField(max_length=2)), - ("union_member", models.BooleanField(default=False)), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('signed_date', models.DateTimeField(default=django.utils.timezone.now)), + ('petition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='index.Petition')), + ('signer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), migrations.AddField( - model_name="signature", - name="signer", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="signatures", - to="index.User", - ), - ), - migrations.AddField( - model_name="petition", - name="author", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="petitions", - to="index.User", - ), - ), - migrations.AddField( - model_name="petition", - name="senate_response", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="petitions", - to="index.Response", - ), + model_name='petition', + name='senate_response', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='petition_response', to='index.Response'), ), migrations.AddField( - model_name="petition", - name="signatures", - field=models.ManyToManyField( - related_name="petitions", to="index.Signature" - ), + model_name='petition', + name='signatures', + field=models.ManyToManyField(blank=True, related_name='petition_signatures', through='index.Signature', to=settings.AUTH_USER_MODEL), ), migrations.AddField( - model_name="petition", - name="tags", - field=models.ManyToManyField(related_name="petitions", to="index.Tag"), + model_name='petition', + name='tags', + field=models.ManyToManyField(blank=True, related_name='petition_tags', to='index.Tag'), ), ] diff --git a/index/migrations/0002_auto_20190215_0130.py b/index/migrations/0002_auto_20190215_0130.py deleted file mode 100644 index 1252f9a..0000000 --- a/index/migrations/0002_auto_20190215_0130.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 2.1.1 on 2019-02-15 01:30 - -import datetime -from django.db import migrations, models -from django.utils.timezone import utc - - -class Migration(migrations.Migration): - - dependencies = [("index", "0001_initial")] - - operations = [ - migrations.AlterField( - model_name="petition", - name="created_date", - field=models.DateTimeField( - db_index=True, - default=datetime.datetime(2019, 2, 15, 1, 30, 44, 768987, tzinfo=utc), - ), - ), - migrations.AlterField( - model_name="signature", - name="signed_date", - field=models.DateTimeField( - default=datetime.datetime(2019, 2, 15, 1, 30, 44, 767805, tzinfo=utc) - ), - ), - ] diff --git a/index/migrations/0003_auto_20190215_0136.py b/index/migrations/0003_auto_20190215_0136.py deleted file mode 100644 index c4384b8..0000000 --- a/index/migrations/0003_auto_20190215_0136.py +++ /dev/null @@ -1,68 +0,0 @@ -# Generated by Django 2.1.1 on 2019-02-15 01:36 - -import datetime -from django.db import migrations, models -import django.db.models.deletion -from django.utils.timezone import utc - - -class Migration(migrations.Migration): - - dependencies = [("index", "0002_auto_20190215_0130")] - - operations = [ - migrations.AlterField( - model_name="petition", - name="ID", - field=models.IntegerField(primary_key=True, serialize=False), - ), - migrations.AlterField( - model_name="petition", - name="author", - field=models.ForeignKey( - blank=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="petitions", - to="index.User", - ), - ), - migrations.AlterField( - model_name="petition", - name="created_date", - field=models.DateTimeField( - db_index=True, - default=datetime.datetime(2019, 2, 15, 1, 36, 53, 117699, tzinfo=utc), - ), - ), - migrations.AlterField( - model_name="petition", - name="senate_response", - field=models.ForeignKey( - blank=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="petitions", - to="index.Response", - ), - ), - migrations.AlterField( - model_name="petition", - name="signatures", - field=models.ManyToManyField( - blank=True, related_name="petitions", to="index.Signature" - ), - ), - migrations.AlterField( - model_name="petition", - name="tags", - field=models.ManyToManyField( - blank=True, related_name="petitions", to="index.Tag" - ), - ), - migrations.AlterField( - model_name="signature", - name="signed_date", - field=models.DateTimeField( - default=datetime.datetime(2019, 2, 15, 1, 36, 53, 116985, tzinfo=utc) - ), - ), - ] diff --git a/index/migrations/0004_auto_20190215_0140.py b/index/migrations/0004_auto_20190215_0140.py deleted file mode 100644 index 0b04977..0000000 --- a/index/migrations/0004_auto_20190215_0140.py +++ /dev/null @@ -1,58 +0,0 @@ -# Generated by Django 2.1.1 on 2019-02-15 01:40 - -import datetime -from django.db import migrations, models -import django.db.models.deletion -from django.utils.timezone import utc - - -class Migration(migrations.Migration): - - dependencies = [("index", "0003_auto_20190215_0136")] - - operations = [ - migrations.AlterField( - model_name="petition", - name="author", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="petitions", - to="index.User", - ), - ), - migrations.AlterField( - model_name="petition", - name="created_date", - field=models.DateTimeField( - db_index=True, - default=datetime.datetime(2019, 2, 15, 1, 40, 10, 865395, tzinfo=utc), - ), - ), - migrations.AlterField( - model_name="petition", - name="senate_response", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="petitions", - to="index.Response", - ), - ), - migrations.AlterField( - model_name="petition", - name="tags", - field=models.ManyToManyField( - blank=True, null=True, related_name="petitions", to="index.Tag" - ), - ), - migrations.AlterField( - model_name="signature", - name="signed_date", - field=models.DateTimeField( - default=datetime.datetime(2019, 2, 15, 1, 40, 10, 864180, tzinfo=utc) - ), - ), - ] diff --git a/index/migrations/0005_auto_20190303_0230.py b/index/migrations/0005_auto_20190303_0230.py deleted file mode 100644 index 7789129..0000000 --- a/index/migrations/0005_auto_20190303_0230.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 2.1.7 on 2019-03-03 02:30 - -from django.db import migrations, models -import index.models - - -class Migration(migrations.Migration): - - dependencies = [("index", "0004_auto_20190215_0140")] - - operations = [ - migrations.AlterField( - model_name="petition", - name="created_date", - field=models.DateTimeField( - db_index=True, default=index.models.timezone.now - ), - ), - migrations.AlterField( - model_name="petition", - name="tags", - field=models.ManyToManyField( - blank=True, related_name="petitions", to="index.Tag" - ), - ), - migrations.AlterField( - model_name="signature", - name="signed_date", - field=models.DateTimeField(default=index.models.timezone.now), - ), - ] diff --git a/index/migrations/0006_auto_20190402_1928.py b/index/migrations/0006_auto_20190402_1928.py deleted file mode 100644 index 73d244b..0000000 --- a/index/migrations/0006_auto_20190402_1928.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 2.2 on 2019-04-02 19:28 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [("index", "0005_auto_20190303_0230")] - - operations = [ - migrations.AlterField( - model_name="petition", - name="author", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="petitions", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AlterField( - model_name="signature", - name="signer", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="signatures", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.DeleteModel(name="User"), - ] diff --git a/index/models.py b/index/models.py index f2c1e8d..96918e8 100644 --- a/index/models.py +++ b/index/models.py @@ -14,25 +14,6 @@ def __unicode__(self): def __str__(self): return self.label - -# Logs a signature, there can be many in a single petition -class Signature(models.Model): - # The person trying to sign the petition - signer = models.ForeignKey( - User, on_delete=models.CASCADE, related_name="signatures" - ) - signed_date = models.DateTimeField(default=timezone.now) # When they signed - - # Returns the signer when asked for the initials - def __unicode__(self): - return self.signer - - def get_initials(self): - full_name = self.signer.get_username() - name_modified = "".join([i for i in full_name if not i.isdigit()]) - return name_modified[-1] + name_modified[0] - - # Creates a response based on whether the senate is investigating the topic of the Petition class Response(models.Model): senator_investigation = models.BooleanField(default=False) @@ -112,17 +93,17 @@ class Petition(models.Model): expected_sig = models.IntegerField(300) # The author of the petition author = models.ForeignKey( - User, on_delete=models.CASCADE, related_name="petitions", blank=True, null=True + User, on_delete=models.CASCADE, related_name="author", blank=True, null=True ) # The tags, probably a max of 3 - tags = models.ManyToManyField(Tag, related_name="petitions", blank=True) + tags = models.ManyToManyField(Tag, related_name="tags", blank=True) # The signature - signatures = models.ManyToManyField(Signature, related_name="petitions", blank=True) + signatures = models.ManyToManyField(User, through="Signature", related_name="petition_signatures", blank=True) # If the senate has responded , their answer senate_response = models.ForeignKey( Response, on_delete=models.CASCADE, - related_name="petitions", + related_name="petition_response", blank=True, null=True, ) @@ -162,3 +143,16 @@ def check_tags(self): # def add_tag (self): def get_url(self): return reverse("petition-detail", args=[str(self.ID)]) + +# Logs a signature, there can be many in a single petition +class Signature(models.Model): + # The person trying to sign the petition + signer = models.ForeignKey( + User, on_delete=models.CASCADE + ) + petition = models.ForeignKey(Petition, on_delete=models.CASCADE) + signed_date = models.DateTimeField(default=timezone.now) # When they signed + + # Returns the signer when asked for the initials + def __unicode__(self): + return self.signer From 8c4a2d401fcab461a1166b5b252c9fd3f2efa560 Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 16 Apr 2019 14:32:04 -0400 Subject: [PATCH 27/33] Remove templatetags --- index/templatetags/__init__.py | 0 index/templatetags/sign_tags.py | 11 ----------- 2 files changed, 11 deletions(-) delete mode 100644 index/templatetags/__init__.py delete mode 100644 index/templatetags/sign_tags.py diff --git a/index/templatetags/__init__.py b/index/templatetags/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/index/templatetags/sign_tags.py b/index/templatetags/sign_tags.py deleted file mode 100644 index 04826a3..0000000 --- a/index/templatetags/sign_tags.py +++ /dev/null @@ -1,11 +0,0 @@ -from django import template - -register = template.Library() - - -@register.simple_tag -def user_signed(petition, user): - if petition.signatures.filter(signer=user).exists(): - return True - - return False From 582eca4906035670efa2d4a8a11d32fe3227efd6 Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 16 Apr 2019 14:33:12 -0400 Subject: [PATCH 28/33] Have author sign petition --- index/apps.py | 5 ++--- index/signals.py | 8 ++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 index/signals.py diff --git a/index/apps.py b/index/apps.py index fac4c5c..70e738e 100644 --- a/index/apps.py +++ b/index/apps.py @@ -4,6 +4,5 @@ class IndexConfig(AppConfig): name = "index" - -class ViewAllConfig(AppConfig): - name = "view_all" + def ready(self): + import index.signals diff --git a/index/signals.py b/index/signals.py new file mode 100644 index 0000000..ac767c2 --- /dev/null +++ b/index/signals.py @@ -0,0 +1,8 @@ +from django.db.models.signals import post_save +from django.dispatch import receiver +from .models import Petition, Signature + +@receiver(post_save, sender=Petition) +def petition_created(sender, instance, **kwargs): + instance.signatures.add(instance.author) + \ No newline at end of file From 842a32a1052c0d1f645cb0d4cfbaec3764d997d1 Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 16 Apr 2019 14:34:09 -0400 Subject: [PATCH 29/33] Exclude signatures and id fields --- index/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index/admin.py b/index/admin.py index 5b857aa..57fdb2c 100644 --- a/index/admin.py +++ b/index/admin.py @@ -7,7 +7,7 @@ class TagAdmin(admin.ModelAdmin): class PetitionAdmin(admin.ModelAdmin): - pass + exclude = ('created_date','signatures') admin.site.register(Tag, TagAdmin) From 603731f623874ba193767ea547a5fca060755979 Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 16 Apr 2019 14:35:10 -0400 Subject: [PATCH 30/33] In debug mode, make all users superusers --- petitions/backends.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/petitions/backends.py b/petitions/backends.py index 64b6705..bbce63f 100644 --- a/petitions/backends.py +++ b/petitions/backends.py @@ -4,14 +4,15 @@ import os -class StudentCASBackend(CASBackend): +class StudentCASBackend(CASBackend): def user_can_authenticate(self, user): url = ( "https://webtech.union.rpi.edu/services/identity/valid/" + str(user.username).lower() ) - key = str(os.environ.get("IDENTITY_KEY")) + key = settings.IDENTITY_KEY r = requests.get(url, headers={"Authorization": "Token " + key}) + r.raise_for_status() error = r.json()["error"] if error: return False @@ -19,4 +20,12 @@ def user_can_authenticate(self, user): if not student: return False + user.first_name = r.json()["first_name"] + user.last_name = r.json()["last_name"] + + if settings.DEBUG == True: + user.is_staff = True + user.is_superuser = True + + user.save() return True From 89fdadd9c132a7efa898773080ff6152bb228502 Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 16 Apr 2019 14:45:36 -0400 Subject: [PATCH 31/33] Exit if identity key isn't set --- petitions/settings/base.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/petitions/settings/base.py b/petitions/settings/base.py index 2a40dcd..aaac102 100644 --- a/petitions/settings/base.py +++ b/petitions/settings/base.py @@ -23,6 +23,12 @@ SECRET_KEY = os.environ.get("SECRET_KEY") +if "IDENTITY_KEY" not in os.environ: + sys.stderr.write("Error: The environment variable IDENTITY_KEY must be set.\n") + exit(1) + +IDENTITY_KEY = os.environ.get("IDENTITY_KEY") + ALLOWED_HOSTS = [] From 7b9c091a2b8e835100f6f1971d3d8de94df87b78 Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 16 Apr 2019 14:46:59 -0400 Subject: [PATCH 32/33] Adjust for model changes and templatetag removal --- index/templates/detail.html | 19 +++++++------------ index/views.py | 18 ++++++++++++------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/index/templates/detail.html b/index/templates/detail.html index df95982..99aa90e 100644 --- a/index/templates/detail.html +++ b/index/templates/detail.html @@ -5,7 +5,7 @@

{{ petition.title }}

-
Created by {{ petition.author.rcs_id }}
+
Created by {{ petition.author.get_full_name }} ({{ petition.author.username.lower }})
@@ -18,8 +18,8 @@
Description
Signed by
    - {% for signature in signatures %} -
  • {{ signature.get_initials }}
  • + {% for initial in initials %} +
  • {{ initial }}
  • {% empty %}
  • No signatures yet
  • {% endfor %} @@ -30,17 +30,12 @@
    Signed by
    Take action
    -
    {% csrf_token %} {% if user.is_authenticated %} - - {% load user_signed from sign_tags %} - {% user_signed petition user as signed %} - {% if signed %} + {% if user_signed %} {% else %} - - + {% endif %} @@ -51,9 +46,9 @@
    Take action
    -
    {{signatures.count}} / {{petition.expected_sig}} Signatures
    +
    {{initials|length}} / {{petition.expected_sig}} Signatures
    -
    +
    diff --git a/index/views.py b/index/views.py index 127c434..8a8d0c5 100644 --- a/index/views.py +++ b/index/views.py @@ -26,11 +26,18 @@ def create(request): context = {"form": form} return render(request, "create.html", context=context) - def petition_detail(request, pk): petition = Petition.objects.get(pk=pk) - signatures = petition.signatures.all() + user_signed = False + if petition.signatures.filter(username=request.user.username).exists(): + user_signed = True + + signatures = petition.signatures.all() + initials = [] + for user in signatures: + initials.append(user.first_name[0] + user.last_name[0]) + status = "Goal not met" if petition.check_enough_sigs(): status = "Goal met" @@ -39,7 +46,8 @@ def petition_detail(request, pk): progress_percent = int((petition.signatures.count() / petition.expected_sig) * 100) context = { "petition": petition, - "signatures": signatures, + "user_signed": user_signed, + "initials": initials, "status": status, "date": expiration_date, "progress_percent": progress_percent, @@ -56,9 +64,7 @@ def sign(request): if form.is_valid(): pk = form.cleaned_data["pk"] petition = Petition.objects.get(pk=pk) - new_signature = Signature(signer=request.user) - new_signature.save() - petition.signatures.add(new_signature) + petition.signatures.add(request.user) petition.save() return HttpResponseRedirect("/petition/" + str(pk)) From a7d917f9239c693dce83d79ed46e123ec1343cfe Mon Sep 17 00:00:00 2001 From: garoller Date: Tue, 16 Apr 2019 14:49:59 -0400 Subject: [PATCH 33/33] Run black --- index/admin.py | 2 +- index/migrations/0001_initial.py | 138 ++++++++++++++------ index/migrations/0002_auto_20190412_1638.py | 31 +++++ index/models.py | 10 +- index/signals.py | 2 +- index/views.py | 3 +- petitions/backends.py | 4 +- 7 files changed, 141 insertions(+), 49 deletions(-) create mode 100644 index/migrations/0002_auto_20190412_1638.py diff --git a/index/admin.py b/index/admin.py index 57fdb2c..0040f3c 100644 --- a/index/admin.py +++ b/index/admin.py @@ -7,7 +7,7 @@ class TagAdmin(admin.ModelAdmin): class PetitionAdmin(admin.ModelAdmin): - exclude = ('created_date','signatures') + exclude = ("created_date", "signatures") admin.site.register(Tag, TagAdmin) diff --git a/index/migrations/0001_initial.py b/index/migrations/0001_initial.py index 59bcfb7..5046a5b 100644 --- a/index/migrations/0001_initial.py +++ b/index/migrations/0001_initial.py @@ -10,68 +10,126 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] + dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)] operations = [ migrations.CreateModel( - name='Petition', + name="Petition", fields=[ - ('title', models.CharField(max_length=200)), - ('description', models.CharField(max_length=4000)), - ('ID', models.IntegerField(primary_key=True, serialize=False)), - ('archived', models.BooleanField(default=False)), - ('hidden', models.BooleanField(default=False)), - ('created_date', models.DateTimeField(db_index=True, default=django.utils.timezone.now)), - ('expected_sig', models.IntegerField(verbose_name=300)), - ('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='petition_author', to=settings.AUTH_USER_MODEL)), + ("title", models.CharField(max_length=200)), + ("description", models.CharField(max_length=4000)), + ("ID", models.IntegerField(primary_key=True, serialize=False)), + ("archived", models.BooleanField(default=False)), + ("hidden", models.BooleanField(default=False)), + ( + "created_date", + models.DateTimeField( + db_index=True, default=django.utils.timezone.now + ), + ), + ("expected_sig", models.IntegerField(verbose_name=300)), + ( + "author", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="petition_author", + to=settings.AUTH_USER_MODEL, + ), + ), ], ), migrations.CreateModel( - name='Response', + name="Response", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('senator_investigation', models.BooleanField(default=False)), - ('committee_formed', models.BooleanField(default=False)), - ('vote_resolution', models.BooleanField(default=False)), - ('vote_referendum', models.BooleanField(default=False)), - ('refer_to_other', models.BooleanField(default=False)), - ('investigation_info', models.CharField(max_length=1000)), - ('committee_info', models.CharField(max_length=1000)), - ('resolution_info', models.CharField(max_length=1000)), - ('referendum_info', models.CharField(max_length=1000)), - ('refer_other_info', models.CharField(max_length=1000)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("senator_investigation", models.BooleanField(default=False)), + ("committee_formed", models.BooleanField(default=False)), + ("vote_resolution", models.BooleanField(default=False)), + ("vote_referendum", models.BooleanField(default=False)), + ("refer_to_other", models.BooleanField(default=False)), + ("investigation_info", models.CharField(max_length=1000)), + ("committee_info", models.CharField(max_length=1000)), + ("resolution_info", models.CharField(max_length=1000)), + ("referendum_info", models.CharField(max_length=1000)), + ("refer_other_info", models.CharField(max_length=1000)), ], ), migrations.CreateModel( - name='Tag', + name="Tag", fields=[ - ('label', models.CharField(max_length=15, primary_key=True, serialize=False)), + ( + "label", + models.CharField(max_length=15, primary_key=True, serialize=False), + ) ], ), migrations.CreateModel( - name='Signature', + name="Signature", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('signed_date', models.DateTimeField(default=django.utils.timezone.now)), - ('petition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='index.Petition')), - ('signer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "signed_date", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "petition", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="index.Petition" + ), + ), + ( + "signer", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), ], ), migrations.AddField( - model_name='petition', - name='senate_response', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='petition_response', to='index.Response'), + model_name="petition", + name="senate_response", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="petition_response", + to="index.Response", + ), ), migrations.AddField( - model_name='petition', - name='signatures', - field=models.ManyToManyField(blank=True, related_name='petition_signatures', through='index.Signature', to=settings.AUTH_USER_MODEL), + model_name="petition", + name="signatures", + field=models.ManyToManyField( + blank=True, + related_name="petition_signatures", + through="index.Signature", + to=settings.AUTH_USER_MODEL, + ), ), migrations.AddField( - model_name='petition', - name='tags', - field=models.ManyToManyField(blank=True, related_name='petition_tags', to='index.Tag'), + model_name="petition", + name="tags", + field=models.ManyToManyField( + blank=True, related_name="petition_tags", to="index.Tag" + ), ), ] diff --git a/index/migrations/0002_auto_20190412_1638.py b/index/migrations/0002_auto_20190412_1638.py new file mode 100644 index 0000000..6c05ae3 --- /dev/null +++ b/index/migrations/0002_auto_20190412_1638.py @@ -0,0 +1,31 @@ +# Generated by Django 2.2 on 2019-04-12 16:38 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [("index", "0001_initial")] + + operations = [ + migrations.AlterField( + model_name="petition", + name="author", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="author", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AlterField( + model_name="petition", + name="tags", + field=models.ManyToManyField( + blank=True, related_name="tags", to="index.Tag" + ), + ), + ] diff --git a/index/models.py b/index/models.py index 96918e8..07f0b9c 100644 --- a/index/models.py +++ b/index/models.py @@ -14,6 +14,7 @@ def __unicode__(self): def __str__(self): return self.label + # Creates a response based on whether the senate is investigating the topic of the Petition class Response(models.Model): senator_investigation = models.BooleanField(default=False) @@ -98,7 +99,9 @@ class Petition(models.Model): # The tags, probably a max of 3 tags = models.ManyToManyField(Tag, related_name="tags", blank=True) # The signature - signatures = models.ManyToManyField(User, through="Signature", related_name="petition_signatures", blank=True) + signatures = models.ManyToManyField( + User, through="Signature", related_name="petition_signatures", blank=True + ) # If the senate has responded , their answer senate_response = models.ForeignKey( Response, @@ -144,12 +147,11 @@ def check_tags(self): def get_url(self): return reverse("petition-detail", args=[str(self.ID)]) + # Logs a signature, there can be many in a single petition class Signature(models.Model): # The person trying to sign the petition - signer = models.ForeignKey( - User, on_delete=models.CASCADE - ) + signer = models.ForeignKey(User, on_delete=models.CASCADE) petition = models.ForeignKey(Petition, on_delete=models.CASCADE) signed_date = models.DateTimeField(default=timezone.now) # When they signed diff --git a/index/signals.py b/index/signals.py index ac767c2..f033e0c 100644 --- a/index/signals.py +++ b/index/signals.py @@ -2,7 +2,7 @@ from django.dispatch import receiver from .models import Petition, Signature + @receiver(post_save, sender=Petition) def petition_created(sender, instance, **kwargs): instance.signatures.add(instance.author) - \ No newline at end of file diff --git a/index/views.py b/index/views.py index 8a8d0c5..b246dc9 100644 --- a/index/views.py +++ b/index/views.py @@ -26,6 +26,7 @@ def create(request): context = {"form": form} return render(request, "create.html", context=context) + def petition_detail(request, pk): petition = Petition.objects.get(pk=pk) @@ -37,7 +38,7 @@ def petition_detail(request, pk): initials = [] for user in signatures: initials.append(user.first_name[0] + user.last_name[0]) - + status = "Goal not met" if petition.check_enough_sigs(): status = "Goal met" diff --git a/petitions/backends.py b/petitions/backends.py index bbce63f..dca7e42 100644 --- a/petitions/backends.py +++ b/petitions/backends.py @@ -4,7 +4,7 @@ import os -class StudentCASBackend(CASBackend): +class StudentCASBackend(CASBackend): def user_can_authenticate(self, user): url = ( "https://webtech.union.rpi.edu/services/identity/valid/" @@ -26,6 +26,6 @@ def user_can_authenticate(self, user): if settings.DEBUG == True: user.is_staff = True user.is_superuser = True - + user.save() return True