diff --git a/infoscreen/tests.py b/infoscreen/tests.py index 69ee0fa..e2064d9 100644 --- a/infoscreen/tests.py +++ b/infoscreen/tests.py @@ -1,11 +1,13 @@ """File containing Infoscreen tests.""" -from django.test import TestCase +from django.test import TestCase, Client from infoscreen.models import Rotation from infoscreen.models import SossoInfoItem from django.http import HttpRequest import infoscreen.views +import logging + class InfoscreenTestCase(TestCase): """Test cases for testing infoscreen methods.""" @@ -14,6 +16,7 @@ class InfoscreenTestCase(TestCase): """Create some dummy models.""" Rotation.objects.create(name="test_rot") SossoInfoItem.objects.create() + self.c = Client() def test_rotation_created(self): """Check if the dummy model actually exists.""" @@ -32,7 +35,6 @@ class InfoscreenTestCase(TestCase): That would mean that something meaningful has been included in the response. """ - req = HttpRequest() - resp = infoscreen.views.info_items(req) - content = resp.content.decode('utf-8') + resp = self.c.get('/infoscreen/items') + content = resp.json() self.assertTrue(len(content) > 0) diff --git a/infoscreen/views/__init__.py b/infoscreen/views/__init__.py new file mode 100644 index 0000000..941a415 --- /dev/null +++ b/infoscreen/views/__init__.py @@ -0,0 +1,2 @@ +from infoscreen.views.admin_views import * +from infoscreen.views.public_views import * diff --git a/infoscreen/views.py b/infoscreen/views/admin_views.py similarity index 63% rename from infoscreen/views.py rename to infoscreen/views/admin_views.py index 0636f3d..152859a 100644 --- a/infoscreen/views.py +++ b/infoscreen/views/admin_views.py @@ -5,7 +5,7 @@ from django.http import HttpResponse, HttpResponseBadRequest from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_http_methods from django.contrib.contenttypes.models import ContentType -from django.contrib.auth.decorators import permission_required +from django.contrib.auth.decorators import permission_required, login_required from infoscreen.models import UploadFileForm import sikweb.settings as settings @@ -23,53 +23,22 @@ from infoscreen.models import ImageUploadForm from infoscreen.models import HSLDataModel from infoscreen.models import ApyInfoItem from infoscreen.models import VideoInfoItem -from infoscreen.hsl_fetcher import HSLFetcher -def index(request, idx, *args, **kwargs): - """Render infoscreen index page.""" - return render(request, 'infoscreen_index.html', {'rotation': idx}) - - -@permission_required('infoscreen.change_infoinstance', login_url='/login') +@login_required(login_url='/login') +@permission_required('infoscreen.change_infoinstance', raise_exception=True) def admin(request, *args, **kwargs): """Render infoscreen admin page.""" return render(request, 'infoscreen_admin.html', {}) -def default(request, *args, **kwargs): - """Try getting first rotation item.""" - try: - first = Rotation.objects.all()[0].id - except: - first = 0 - return index(request, first, *args, **kwargs) - - -def get_apy_json(request): - """Render APY diilikone page.""" - return HttpResponse( - requests.get("https://api-diilikone.apy.fi/deals/top-groups").text) - - -@require_http_methods(["GET"]) -def rotation(request, idx, *args, **kwargs): - """Get rotation.""" - try: - rotation = Rotation.objects.get(pk=idx) - except Rotation.DoesNotExist: - resp = HttpResponse('{"error": "Rotation not found"}') - resp.status_code = 404 - return resp - - return HttpResponse(json.dumps(rotation.get_dict())) - - def create_item_generator(model): """Create Infoscreen item generator.""" + @ensure_csrf_cookie @require_http_methods(["POST"]) - @permission_required('infoscreen.change_infoinstance', login_url='/login') + @login_required(login_url='/login') + @permission_required('infoscreen.add_infoinstance', raise_exception=True) def create_item(request, *args, **kwargs): try: data = json.loads(request.body.decode("utf-8")) @@ -87,9 +56,11 @@ def create_item_generator(model): def delete_item_generator(model): """Delete Infoscreen item generator.""" + @ensure_csrf_cookie @require_http_methods(["DELETE"]) - @permission_required('infoscreen.change_infoinstance', login_url='/login') + @login_required(login_url='/login') + @permission_required('infoscreen.delete_infoinstance', raise_exception=True) def delete_item(request, *args, **kwargs): idx = kwargs.pop("idx", 0) try: @@ -110,7 +81,8 @@ def delete_item_generator(model): # due to model structure this is little complicated @ensure_csrf_cookie -@permission_required('infoscreen.change_infoinstance', login_url='/login') +@login_required(login_url='/login') +@permission_required('infoscreen.delete_infoinstance', raise_exception=True) @require_http_methods(["DELETE"]) def delete_info_item(request, *args, **kwargs): """Delete info item.""" @@ -132,39 +104,10 @@ def delete_info_item(request, *args, **kwargs): return resp -@require_http_methods(["GET"]) -def rotations(request, *args, **kwargs): - """Return rotation lists.""" - rotations = list(map(lambda r: r.get_list(), Rotation.objects.all())) - return HttpResponse(json.dumps(rotations)) - - -@require_http_methods(["GET"]) -def info_types(request, *args, **kwargs): - """Return info item types.""" - types = [] - classes = InfoItem.get_subclasses() - for c in classes: - types.append({ - "name": c.display_name, - "create_template_url": c.get_create_template_url(), - }) - return HttpResponse(json.dumps(types)) - - -def info_items(request, *args, **kwargs): - """Return Infoscreen items.""" - items = [] - classes = InfoItem.get_subclasses() - for c in classes: - for i in c.objects.all(): - items.append(i.get_dict()) - return HttpResponse(json.dumps(items)) - - @require_http_methods(["POST"]) @ensure_csrf_cookie -@permission_required('infoscreen.change_infoinstance', login_url='/login') +@login_required(login_url='/login') +@permission_required('infoscreen.add_infoinstance', raise_exception=True) def create_image_item(request, *args, **kwargs): """Create image Infoscreen item.""" form = ImageUploadForm(request.POST, request.FILES) @@ -180,7 +123,8 @@ def create_image_item(request, *args, **kwargs): @require_http_methods(["POST"]) @ensure_csrf_cookie -@permission_required('infoscreen.change_infoinstance', login_url='/login') +@login_required(login_url='/login') +@permission_required('infoscreen.add_infoinstance', raise_exception=True) def create_video_item(request, *args, **kwargs): """Create video Infoscreen item.""" form = UploadFileForm(request.POST, request.FILES) @@ -196,7 +140,8 @@ def create_video_item(request, *args, **kwargs): @require_http_methods(["POST"]) @ensure_csrf_cookie -@permission_required('infoscreen.add_rotation', login_url='/login') +@login_required(login_url='/login') +@permission_required('infoscreen.add_rotation', raise_exception=True) def create_rotation(request, *args, **kwargs): """Create rotation.""" try: @@ -217,7 +162,8 @@ def create_rotation(request, *args, **kwargs): @require_http_methods(["DELETE"]) @ensure_csrf_cookie -@permission_required('infoscreen.delete_rotation', login_url='/login') +@login_required(login_url='/login') +@permission_required('infoscreen.delete_rotation', raise_exception=True) def delete_rotation(request, *args, **kwargs): """Delete rotation.""" id = kwargs.pop("id", 0) @@ -233,32 +179,6 @@ def delete_rotation(request, *args, **kwargs): return resp -@require_http_methods(["GET"]) -def hsl_timetable_settings(request, *args, **kwargs): - """Set HSL timetable settings.""" - d = {"departure_threshold": settings.HSL_DEPARTURE_THRESHOLD, - "hurry_threshold": settings.HSL_HURRY_THRESHOLD} - resp = json.dumps(d) - return HttpResponse(resp, status=200) - - -@require_http_methods(["GET"]) -def CurrentHSLView(request, *args, **kwargs): - """Get HSL data and return it.""" - fetcher = HSLFetcher() - fetcherThread = threading.Thread(target=fetcher.fetch_if_needed, args=[]) - fetcherThread.setDaemon(False) - fetcherThread.start() - - data = HSLDataModel.objects.all() - if len(data) < 1: - return HttpResponse( - '{"error" : "Could not find timetables from database."}', - status=500) - - return HttpResponse(data[len(data) - 1].data, status=200) - - createInstance = create_item_generator(InfoInstance) deleteInstance = delete_item_generator(InfoInstance) createABBItem = create_item_generator(ABBInfoItem) diff --git a/infoscreen/views/public_views.py b/infoscreen/views/public_views.py new file mode 100644 index 0000000..461a547 --- /dev/null +++ b/infoscreen/views/public_views.py @@ -0,0 +1,103 @@ +from django.shortcuts import render +from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest +from django.views.decorators.http import require_http_methods + +from infoscreen.models import Rotation, InfoItem, InfoInstance +from infoscreen.hsl_fetcher import HSLFetcher + +import json +import logging + + +@require_http_methods(["GET"]) +def index(request, idx, *args, **kwargs): + """Render infoscreen index page.""" + return render(request, 'infoscreen_index.html', {'rotation': idx}) + + +@require_http_methods(["GET"]) +def default(request, *args, **kwargs): + """Try getting first rotation item.""" + try: + first = Rotation.objects.all()[0].id + except: + first = 0 + return index(request, first, *args, **kwargs) + + +@require_http_methods(["GET"]) +def get_apy_json(request): + """Render APY diilikone page.""" + return HttpResponse( + requests.get("https://api-diilikone.apy.fi/deals/top-groups").text) + + +@require_http_methods(["GET"]) +def rotation(request, idx, *args, **kwargs): + """Get rotation.""" + try: + rotation = Rotation.objects.get(pk=idx) + except Rotation.DoesNotExist: + resp = HttpResponse('{"error": "Rotation not found"}') + resp.status_code = 404 + return resp + + return HttpResponse(json.dumps(rotation.get_dict())) + + +@require_http_methods(["GET"]) +def rotations(request, *args, **kwargs): + """Return rotation lists.""" + rotations = list(map(lambda r: r.get_list(), Rotation.objects.all())) + return HttpResponse(json.dumps(rotations)) + + +@require_http_methods(["GET"]) +def info_types(request, *args, **kwargs): + """Return info item types.""" + types = [] + classes = InfoItem.get_subclasses() + for c in classes: + types.append({ + "name": c.display_name, + "create_template_url": c.get_create_template_url(), + }) + return HttpResponse(json.dumps(types)) + + +@require_http_methods(["GET"]) +def info_items(request, *args, **kwargs): + """Return Infoscreen items.""" + items = [] + classes = InfoItem.get_subclasses() + for c in classes: + for i in c.objects.all(): + items.append(i.get_dict()) + + return JsonResponse(items, safe=False) + + +@require_http_methods(["GET"]) +def hsl_timetable_settings(request, *args, **kwargs): + """Set HSL timetable settings.""" + d = {"departure_threshold": settings.HSL_DEPARTURE_THRESHOLD, + "hurry_threshold": settings.HSL_HURRY_THRESHOLD} + resp = json.dumps(d) + return HttpResponse(resp, status=200) + + +@require_http_methods(["GET"]) +def CurrentHSLView(request, *args, **kwargs): + """Get HSL data and return it.""" + fetcher = HSLFetcher() + fetcherThread = threading.Thread(target=fetcher.fetch_if_needed, args=[]) + fetcherThread.setDaemon(False) + fetcherThread.start() + + data = HSLDataModel.objects.all() + if len(data) < 1: + return HttpResponse( + '{"error" : "Could not find timetables from database."}', + status=500) + + return HttpResponse(data[len(data) - 1].data, status=200) diff --git a/locale/en/LC_MESSAGES/django.mo b/locale/en/LC_MESSAGES/django.mo index 843785a..d8f27f1 100644 Binary files a/locale/en/LC_MESSAGES/django.mo and b/locale/en/LC_MESSAGES/django.mo differ diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index 8c429ff..afde5f3 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-09-27 19:01+0300\n" +"POT-Creation-Date: 2017-09-28 23:40+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -33,7 +33,7 @@ msgstr "External website" msgid "Sössö articles" msgstr "Sössö articles" -#: infoscreen/models.py:199 +#: infoscreen/models.py:199 webapp/models.py:70 msgid "Events" msgstr "Events" @@ -81,10 +81,8 @@ msgid "Create new item" msgstr "Create new item" #: infoscreen/templates/infoscreen_admin.html:50 -#, fuzzy -#| msgid "Create new item" msgid "Create a new item by type" -msgstr "Create new item" +msgstr "Create a new item by type" #: infoscreen/templates/infoscreen_admin.html:53 msgid "Item type" @@ -169,8 +167,8 @@ msgstr "Select rotation to edit" msgid "id" msgstr "id" -#: infoscreen/templates/infoscreen_admin.html:141 webapp/models.py:60 -#: webapp/models.py:94 webapp/models.py:107 +#: infoscreen/templates/infoscreen_admin.html:141 webapp/models.py:91 +#: webapp/models.py:125 webapp/models.py:138 msgid "Name" msgstr "Name" @@ -184,12 +182,12 @@ msgid "Language" msgstr "Language" #: infoscreen/templates/infoscreen_admin.html:161 -#: members/templates/settings.html:20 sikweb/base.py:220 +#: members/templates/settings.html:20 sikweb/base.py:221 msgid "Finnish" msgstr "Finnish" #: infoscreen/templates/infoscreen_admin.html:162 -#: members/templates/settings.html:21 sikweb/base.py:221 +#: members/templates/settings.html:21 sikweb/base.py:222 msgid "English" msgstr "English" @@ -212,7 +210,7 @@ msgstr "First name" msgid "Last name" msgstr "Last name" -#: members/models.py:16 webapp/models.py:95 webapp/models.py:108 +#: members/models.py:16 webapp/models.py:126 webapp/models.py:139 msgid "Email" msgstr "Email" @@ -220,7 +218,7 @@ msgstr "Email" msgid "Place of residence" msgstr "Place of residence" -#: members/models.py:19 members/models.py:60 +#: members/models.py:19 members/models.py:70 #: members/templates/member_add_many.html:35 msgid "AYY" msgstr "AYY" @@ -229,27 +227,27 @@ msgstr "AYY" msgid "JAS" msgstr "JAS" -#: members/models.py:46 +#: members/models.py:51 msgid "Submitted" msgstr "Submitted" -#: members/models.py:58 +#: members/models.py:68 msgid "Date" msgstr "Date" -#: members/models.py:59 +#: members/models.py:69 msgid "Source" msgstr "Source" -#: members/models.py:61 +#: members/models.py:71 msgid "Cash" msgstr "Cash" -#: members/models.py:62 members/templates/member_add_many.html:36 +#: members/models.py:72 members/templates/member_add_many.html:36 msgid "Bank transfer" msgstr "Bank transfer" -#: members/models.py:86 +#: members/models.py:96 msgid "Created" msgstr "Created" @@ -453,130 +451,190 @@ msgstr "Payment events" msgid "Payments in register:" msgstr "Member register" -#: members/views/applications.py:49 members/views/applications.py:96 -#: members/views/applications.py:124 +#: members/views/applications.py:51 members/views/applications.py:100 +#: members/views/applications.py:129 msgid "No application id specified" msgstr "No application id specified" -#: members/views/applications.py:77 +#: members/views/applications.py:80 msgid "Successfully accepted application" msgstr "Successfully accepted application" -#: members/views/applications.py:84 +#: members/views/applications.py:87 msgid "Could not accept application object" msgstr "Could not accept application object" -#: members/views/applications.py:100 +#: members/views/applications.py:104 msgid "Successfully deleted application" msgstr "Successfully deleted application" -#: members/views/applications.py:112 +#: members/views/applications.py:116 msgid "Could not delete application object" msgstr "Could not delete application object" -#: members/views/members.py:71 members/views/members.py:164 -#: members/views/members.py:190 +#: members/views/members.py:74 members/views/members.py:172 +#: members/views/members.py:199 msgid "No member id specified" msgstr "No member id specified" -#: members/views/members.py:106 +#: members/views/members.py:111 msgid "Failed to import members" msgstr "Failed to import members" -#: members/views/members.py:119 +#: members/views/members.py:125 msgid "Successfully added member" msgstr "Successfully added member" -#: members/views/members.py:144 +#: members/views/members.py:151 msgid "Successfully updated member" msgstr "Successfully updated member" -#: members/views/members.py:152 +#: members/views/members.py:159 msgid "Could not update member object" msgstr "Could not update member object" -#: members/views/members.py:168 +#: members/views/members.py:176 msgid "Successfully deleted member" msgstr "Successfully deleted member" -#: members/views/members.py:179 +#: members/views/members.py:187 msgid "Could not delete member object" msgstr "Could not delete member object" -#: members/views/payments.py:67 +#: members/views/payments.py:70 msgid "Successfully added payment for member" msgstr "Successfully added payment for member" -#: members/views/payments.py:85 members/views/payments.py:103 -#: members/views/payments.py:122 +#: members/views/payments.py:89 members/views/payments.py:108 +#: members/views/payments.py:128 msgid "No payment id specified" msgstr "No payment id specified" -#: members/views/payments.py:127 +#: members/views/payments.py:133 msgid "Successfully deleted payment" msgstr "Successfully deleted payment" -#: members/views/payments.py:137 +#: members/views/payments.py:143 msgid "Could not delete payment object" msgstr "Could not delete payment object" -#: members/views/payments.py:156 +#: members/views/payments.py:163 msgid "Successfully updated payment" msgstr "Successfully updated payment" -#: members/views/payments.py:163 +#: members/views/payments.py:170 msgid "Could not update payment object" msgstr "Could not update payment object" -#: members/views/utils.py:113 +#: members/views/utils.py:115 msgid "Missing \"textfield\" POST request field" msgstr "Missing \"textfield\" POST request field" +#: templates/admin/base_site.html:43 +msgid "Go" +msgstr "" + #: templates/footer.html:7 msgid "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" msgstr "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" -#: webapp/models.py:61 +#: webapp/models.py:15 +msgid "Webapp" +msgstr "" + +#: webapp/models.py:26 +msgid "Tag" +msgstr "" + +#: webapp/models.py:27 +msgid "Tags" +msgstr "" + +#: webapp/models.py:30 +msgid "Tag: {}" +msgstr "" + +#: webapp/models.py:50 +msgid "Feed: {}" +msgstr "" + +#: webapp/models.py:53 +msgid "Feed" +msgstr "" + +#: webapp/models.py:54 +msgid "Feeds" +msgstr "" + +#: webapp/models.py:66 +#, fuzzy +#| msgid "Events" +msgid "Event: {}" +msgstr "Events" + +#: webapp/models.py:69 +#, fuzzy +#| msgid "Events" +msgid "Event" +msgstr "Events" + +#: webapp/models.py:81 +msgid "Registration: {}" +msgstr "" + +#: webapp/models.py:84 +#, fuzzy +#| msgid "Rotation" +msgid "Registration" +msgstr "Rotation" + +#: webapp/models.py:85 +#, fuzzy +#| msgid "Rotations" +msgid "Registrations" +msgstr "Rotations" + +#: webapp/models.py:92 #, fuzzy #| msgid "Add member" msgid "Board member" msgstr "Add member" -#: webapp/models.py:67 +#: webapp/models.py:98 #, fuzzy #| msgid "Duration" msgid "Description" msgstr "Duration" -#: webapp/models.py:68 +#: webapp/models.py:99 msgid "Summary" msgstr "" -#: webapp/models.py:96 +#: webapp/models.py:127 msgid "Message" msgstr "" -#: webapp/models.py:109 +#: webapp/models.py:140 msgid "Year" msgstr "" -#: webapp/models.py:123 +#: webapp/models.py:154 msgid "Role" msgstr "" -#: webapp/models.py:125 +#: webapp/models.py:156 msgid "Start date" msgstr "" -#: webapp/models.py:126 +#: webapp/models.py:157 msgid "End date" msgstr "" -#: webapp/models.py:136 +#: webapp/models.py:167 msgid "Official" msgstr "" -#: webapp/models.py:138 +#: webapp/models.py:169 msgid "Phone number" msgstr "" @@ -588,6 +646,30 @@ msgstr "SIK Admin" msgid "Aalto-yliopiston Sähköinsinöörikilta ry" msgstr "Aalto-yliopiston Sähköinsinöörikilta ry" +#: webapp/templates/contact.html:7 webapp/templates/navigation.html:32 +msgid "Contact" +msgstr "Contact" + +#: webapp/templates/event_calendar.html:7 webapp/templates/navigation.html:29 +msgid "Event calendar" +msgstr "Event calendar" + +#: webapp/templates/freshmen.html:7 webapp/templates/navigation.html:16 +msgid "Freshmen" +msgstr "Freshmen" + +#: webapp/templates/guild.html:7 +msgid "Kilta" +msgstr "Guild" + +#: webapp/templates/international.html:7 webapp/templates/navigation.html:30 +msgid "International" +msgstr "International" + +#: webapp/templates/jobs.html:7 webapp/templates/navigation.html:20 +msgid "Jobs" +msgstr "Jobs" + #: webapp/templates/login.html:25 webapp/templates/login.html:27 msgid "Username" msgstr "Username" @@ -612,34 +694,14 @@ msgstr "Admin tools" msgid "Guild" msgstr "Guild" -#: webapp/templates/navigation.html:16 -msgid "Freshmen" -msgstr "Freshmen" - #: webapp/templates/navigation.html:18 msgid "Corporate" msgstr "Corporate" -#: webapp/templates/navigation.html:20 -msgid "Jobs" -msgstr "Jobs" - -#: webapp/templates/navigation.html:29 -msgid "Event calendar" -msgstr "Event calendar" - -#: webapp/templates/navigation.html:30 -msgid "International" -msgstr "International" - -#: webapp/templates/navigation.html:31 +#: webapp/templates/navigation.html:31 webapp/templates/sosso.html:7 msgid "Sössö" msgstr "Sössö" -#: webapp/templates/navigation.html:32 -msgid "Contact" -msgstr "Contact" - #: webapp/templates/ohlhafv.html:8 msgid "Ohlhafv" msgstr "Ohlhafv" @@ -656,6 +718,11 @@ msgstr "All challenges" msgid "Total challenges:" msgstr "Total challenges:" +#, fuzzy +#~| msgid "Language" +#~ msgid "language" +#~ msgstr "Language" + #~ msgid "Successfully imported multiple members" #~ msgstr "Successfully imported multiple members" diff --git a/locale/fi/LC_MESSAGES/django.mo b/locale/fi/LC_MESSAGES/django.mo index bf328d3..619b7a6 100644 Binary files a/locale/fi/LC_MESSAGES/django.mo and b/locale/fi/LC_MESSAGES/django.mo differ diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po index dd1a3fd..758ca35 100644 --- a/locale/fi/LC_MESSAGES/django.po +++ b/locale/fi/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-09-27 19:01+0300\n" +"POT-Creation-Date: 2017-09-28 23:40+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -34,7 +34,7 @@ msgstr "Ulkoinen verkkosivu" msgid "Sössö articles" msgstr "Sössön artikkelit" -#: infoscreen/models.py:199 +#: infoscreen/models.py:199 webapp/models.py:70 msgid "Events" msgstr "Tapahtumat" @@ -168,8 +168,8 @@ msgstr "Valitse muokattava rotaatio" msgid "id" msgstr "id" -#: infoscreen/templates/infoscreen_admin.html:141 webapp/models.py:60 -#: webapp/models.py:94 webapp/models.py:107 +#: infoscreen/templates/infoscreen_admin.html:141 webapp/models.py:91 +#: webapp/models.py:125 webapp/models.py:138 msgid "Name" msgstr "Nimi" @@ -183,12 +183,12 @@ msgid "Language" msgstr "Kieli" #: infoscreen/templates/infoscreen_admin.html:161 -#: members/templates/settings.html:20 sikweb/base.py:220 +#: members/templates/settings.html:20 sikweb/base.py:221 msgid "Finnish" msgstr "suomi" #: infoscreen/templates/infoscreen_admin.html:162 -#: members/templates/settings.html:21 sikweb/base.py:221 +#: members/templates/settings.html:21 sikweb/base.py:222 msgid "English" msgstr "englanti" @@ -209,7 +209,7 @@ msgstr "Etunimi" msgid "Last name" msgstr "Sukunimi" -#: members/models.py:16 webapp/models.py:95 webapp/models.py:108 +#: members/models.py:16 webapp/models.py:126 webapp/models.py:139 msgid "Email" msgstr "Sähköposti" @@ -217,7 +217,7 @@ msgstr "Sähköposti" msgid "Place of residence" msgstr "Asuinpaikka" -#: members/models.py:19 members/models.py:60 +#: members/models.py:19 members/models.py:70 #: members/templates/member_add_many.html:35 msgid "AYY" msgstr "AYY" @@ -226,27 +226,27 @@ msgstr "AYY" msgid "JAS" msgstr "JAS" -#: members/models.py:46 +#: members/models.py:51 msgid "Submitted" msgstr "Lisätty" -#: members/models.py:58 +#: members/models.py:68 msgid "Date" msgstr "Päivämäärä" -#: members/models.py:59 +#: members/models.py:69 msgid "Source" msgstr "Lähde" -#: members/models.py:61 +#: members/models.py:71 msgid "Cash" msgstr "Käteinen" -#: members/models.py:62 members/templates/member_add_many.html:36 +#: members/models.py:72 members/templates/member_add_many.html:36 msgid "Bank transfer" msgstr "Tilisiirto" -#: members/models.py:86 +#: members/models.py:96 msgid "Created" msgstr "Lisätty" @@ -443,126 +443,178 @@ msgstr "Maksutapahtumat" msgid "Payments in register:" msgstr "Maksutapahtumia:" -#: members/views/applications.py:49 members/views/applications.py:96 -#: members/views/applications.py:124 +#: members/views/applications.py:51 members/views/applications.py:100 +#: members/views/applications.py:129 msgid "No application id specified" msgstr "Hakemuksen ID ei määritelty" -#: members/views/applications.py:77 +#: members/views/applications.py:80 msgid "Successfully accepted application" msgstr "Onnistuneesti hyväksyttiin hakemus" -#: members/views/applications.py:84 +#: members/views/applications.py:87 msgid "Could not accept application object" msgstr "Hakemusobjektia ei voitu hyväksyä" -#: members/views/applications.py:100 +#: members/views/applications.py:104 msgid "Successfully deleted application" msgstr "Onnistuneesti poistettiin hakemus" -#: members/views/applications.py:112 +#: members/views/applications.py:116 msgid "Could not delete application object" msgstr "Hakemusobjektia ei voitu poistaa" -#: members/views/members.py:71 members/views/members.py:164 -#: members/views/members.py:190 +#: members/views/members.py:74 members/views/members.py:172 +#: members/views/members.py:199 msgid "No member id specified" msgstr "Jäsenen ID ei määritelty" -#: members/views/members.py:106 +#: members/views/members.py:111 msgid "Failed to import members" msgstr "Jäsenten tuonti epäonnistui" -#: members/views/members.py:119 +#: members/views/members.py:125 msgid "Successfully added member" msgstr "Onnistuneesti lisättiin jäsen" -#: members/views/members.py:144 +#: members/views/members.py:151 msgid "Successfully updated member" msgstr "Onnistuneesti päivitettiin jäsen" -#: members/views/members.py:152 +#: members/views/members.py:159 msgid "Could not update member object" msgstr "Jäsenobjektia ei voitu päivittää" -#: members/views/members.py:168 +#: members/views/members.py:176 msgid "Successfully deleted member" msgstr "Onnistuneesti poistettiin jäsen" -#: members/views/members.py:179 +#: members/views/members.py:187 msgid "Could not delete member object" msgstr "Jäsenobjektia ei voitu poistaa" -#: members/views/payments.py:67 +#: members/views/payments.py:70 msgid "Successfully added payment for member" msgstr "Onnistuneesti lisättiin maksutapahtuma jäsenelle" -#: members/views/payments.py:85 members/views/payments.py:103 -#: members/views/payments.py:122 +#: members/views/payments.py:89 members/views/payments.py:108 +#: members/views/payments.py:128 msgid "No payment id specified" msgstr "Maksutapahtuman ID ei määritelty" -#: members/views/payments.py:127 +#: members/views/payments.py:133 msgid "Successfully deleted payment" msgstr "Onnistuneesti poistettiin maksutapahtuma" -#: members/views/payments.py:137 +#: members/views/payments.py:143 msgid "Could not delete payment object" msgstr "Maksutapahtumaobjektia ei voitu poistaa" -#: members/views/payments.py:156 +#: members/views/payments.py:163 msgid "Successfully updated payment" msgstr "Onnistuneesti päivitettiin maksutapahtuma" -#: members/views/payments.py:163 +#: members/views/payments.py:170 msgid "Could not update payment object" msgstr "Maksutapahtumaobjektia ei voitu päivittää" -#: members/views/utils.py:113 +#: members/views/utils.py:115 msgid "Missing \"textfield\" POST request field" msgstr "Puuttuva \"textfield\" POST-kenttä" +#: templates/admin/base_site.html:43 +msgid "Go" +msgstr "Vaihda" + #: templates/footer.html:7 msgid "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" msgstr "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" -#: webapp/models.py:61 +#: webapp/models.py:15 +msgid "Webapp" +msgstr "Nettisivut" + +#: webapp/models.py:26 +msgid "Tag" +msgstr "Tunniste" + +#: webapp/models.py:27 +msgid "Tags" +msgstr "Tunnisteet" + +#: webapp/models.py:30 +msgid "Tag: {}" +msgstr "Tunniste: {}" + +#: webapp/models.py:50 +msgid "Feed: {}" +msgstr "Uutinen: {}" + +#: webapp/models.py:53 +msgid "Feed" +msgstr "Uutinen" + +#: webapp/models.py:54 +msgid "Feeds" +msgstr "Uutiset" + +#: webapp/models.py:66 +msgid "Event: {}" +msgstr "Tapahtuma: {}" + +#: webapp/models.py:69 +msgid "Event" +msgstr "Tapahtuma" + +#: webapp/models.py:81 +msgid "Registration: {}" +msgstr "Registration: {}" + +#: webapp/models.py:84 +msgid "Registration" +msgstr "Ilmoittautuminen" + +#: webapp/models.py:85 +msgid "Registrations" +msgstr "Ilmoittautumiset" + +#: webapp/models.py:92 msgid "Board member" msgstr "Hallituksen jäsen" -#: webapp/models.py:67 +#: webapp/models.py:98 msgid "Description" msgstr "Kuvaus" -#: webapp/models.py:68 +#: webapp/models.py:99 msgid "Summary" msgstr "Tiivistelmä" -#: webapp/models.py:96 +#: webapp/models.py:127 msgid "Message" msgstr "Viesti" -#: webapp/models.py:109 +#: webapp/models.py:140 msgid "Year" msgstr "Vuosi" -#: webapp/models.py:123 +#: webapp/models.py:154 msgid "Role" msgstr "Rooli" -#: webapp/models.py:125 +#: webapp/models.py:156 msgid "Start date" msgstr "Alkupäivämäärä" -#: webapp/models.py:126 +#: webapp/models.py:157 msgid "End date" msgstr "Loppupäivämäärä" -#: webapp/models.py:136 +#: webapp/models.py:167 msgid "Official" msgstr "Toimihenkilö" -#: webapp/models.py:138 +#: webapp/models.py:169 msgid "Phone number" msgstr "Puhelinnumero" @@ -574,6 +626,30 @@ msgstr "SIK Hallintapaneeli" msgid "Aalto-yliopiston Sähköinsinöörikilta ry" msgstr "Aalto-yliopiston Sähköinsinöörikilta ry" +#: webapp/templates/contact.html:7 webapp/templates/navigation.html:32 +msgid "Contact" +msgstr "Yhteystiedot" + +#: webapp/templates/event_calendar.html:7 webapp/templates/navigation.html:29 +msgid "Event calendar" +msgstr "Tapahtumakalenteri" + +#: webapp/templates/freshmen.html:7 webapp/templates/navigation.html:16 +msgid "Freshmen" +msgstr "Fuksit" + +#: webapp/templates/guild.html:7 +msgid "Kilta" +msgstr "" + +#: webapp/templates/international.html:7 webapp/templates/navigation.html:30 +msgid "International" +msgstr "International" + +#: webapp/templates/jobs.html:7 webapp/templates/navigation.html:20 +msgid "Jobs" +msgstr "Työpaikat" + #: webapp/templates/login.html:25 webapp/templates/login.html:27 msgid "Username" msgstr "Käyttäjänimi" @@ -598,34 +674,14 @@ msgstr "Hallintatyökalut" msgid "Guild" msgstr "Kilta" -#: webapp/templates/navigation.html:16 -msgid "Freshmen" -msgstr "Fuksit" - #: webapp/templates/navigation.html:18 msgid "Corporate" msgstr "Yritys" -#: webapp/templates/navigation.html:20 -msgid "Jobs" -msgstr "Työpaikat" - -#: webapp/templates/navigation.html:29 -msgid "Event calendar" -msgstr "Tapahtumakalenteri" - -#: webapp/templates/navigation.html:30 -msgid "International" -msgstr "International" - -#: webapp/templates/navigation.html:31 +#: webapp/templates/navigation.html:31 webapp/templates/sosso.html:7 msgid "Sössö" msgstr "Sössö" -#: webapp/templates/navigation.html:32 -msgid "Contact" -msgstr "Yhteystiedot" - #: webapp/templates/ohlhafv.html:8 msgid "Ohlhafv" msgstr "Øhlhäfv" @@ -641,3 +697,6 @@ msgstr "Kaikki haasteet" #: webapp/templates/ohlhafv_list.html:15 msgid "Total challenges:" msgstr "Haasteita yhteensä:" + +#~ msgid "language" +#~ msgstr "Kieli" diff --git a/members/migrations/0018_auto_20170927_1918.py b/members/migrations/0018_auto_20170927_1918.py new file mode 100644 index 0000000..0c601a9 --- /dev/null +++ b/members/migrations/0018_auto_20170927_1918.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-09-27 16:18 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0017_auto_20170926_1316'), + ] + + operations = [ + migrations.AlterModelOptions( + name='member', + options={'permissions': (('check_by_email', 'Can check if user exists by email'), ('read_member', 'Can see member in list'))}, + ), + migrations.AlterModelOptions( + name='payment', + options={'permissions': (('read_payment', 'Can see payment in list'),)}, + ), + migrations.AlterModelOptions( + name='request', + options={'permissions': (('read_application', 'Can see member application in list'),)}, + ), + ] diff --git a/members/models.py b/members/models.py index 7e4d7ea..8f36dbc 100644 --- a/members/models.py +++ b/members/models.py @@ -43,6 +43,11 @@ class BaseMember(models.Model): class Request(BaseMember): """Member request model represents one member request.""" + class Meta: + permissions = ( + ('read_application', 'Can see member application in list'), + ) + submitted = models.DateTimeField(_('Submitted'), default=timezone.now) def to_member(self): @@ -55,6 +60,11 @@ class Request(BaseMember): class Payment(models.Model): """Payment model representing one payment event.""" + class Meta: + permissions = ( + ('read_payment', 'Can see payment in list'), + ) + date = models.DateTimeField(_('Date'), default=timezone.now) source = models.CharField(_('Source'), choices=[ ('AYY', _('AYY')), @@ -88,6 +98,7 @@ class Member(BaseMember): class Meta: permissions = ( ('check_by_email', 'Can check if user exists by email'), + ('read_member', 'Can see member in list'), ) def last_paid(self): diff --git a/members/views/applications.py b/members/views/applications.py index 9207fd7..8324d53 100644 --- a/members/views/applications.py +++ b/members/views/applications.py @@ -1,5 +1,5 @@ from django.shortcuts import render -from django.contrib.auth.decorators import permission_required +from django.contrib.auth.decorators import permission_required, login_required from django.views.decorators.http import require_http_methods from django.views.decorators.csrf import ensure_csrf_cookie from django.http import HttpResponse, HttpResponseRedirect @@ -18,7 +18,8 @@ from members.forms import ApplicationForm @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.read_application', raise_exception=True) def application_list(request, *args, **kwargs): """List member applications not yet processed.""" applications = Request.objects.all() @@ -40,7 +41,8 @@ def application_list(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.change_request', raise_exception=True) def application_edit(request, *args, **kwargs): """Edit member request information.""" i = kwargs.pop('index', None) @@ -58,7 +60,8 @@ def application_edit(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["POST"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.add_member', raise_exception=True) def application_accept(request, *args, **kwargs): """Accept application.""" form = ApplicationForm(request.POST) @@ -86,7 +89,8 @@ def application_accept(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["POST"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.delete_request', raise_exception=True) def application_delete(request, *args, **kwargs): """Delete member application.""" try: @@ -114,7 +118,8 @@ def application_delete(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.delete_request', raise_exception=True) def application_delete_confirm(request, *args, **kwargs): """Confirm application deletion.""" i = kwargs.pop('index', None) diff --git a/members/views/members.py b/members/views/members.py index 16467a9..c50ed79 100644 --- a/members/views/members.py +++ b/members/views/members.py @@ -1,5 +1,5 @@ from django.shortcuts import render -from django.contrib.auth.decorators import permission_required +from django.contrib.auth.decorators import permission_required, login_required from django.utils.decorators import method_decorator from django.views.decorators.http import require_http_methods from django.views.decorators.csrf import ensure_csrf_cookie @@ -27,7 +27,8 @@ from members.views.utils import * @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.read_member', raise_exception=True) def member_list(request, *args, **kwargs): """Render members list.""" search = request.GET.get('q', None) @@ -53,7 +54,8 @@ def member_list(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.add_member', raise_exception=True) def member_add(request, *args, **kwargs): """Render add member page.""" form = MemberForm() @@ -62,7 +64,8 @@ def member_add(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.delete_member', raise_exception=True) def member_delete_confirm(request, *args, **kwargs): """Render member deletion confirmation page.""" i = kwargs.pop('index', None) @@ -78,7 +81,8 @@ def member_delete_confirm(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.add_member', raise_exception=True) def member_add_many(request, *args, **kwargs): """Render add multiple members page.""" return render(request, 'member_add_many.html', {}) @@ -86,7 +90,8 @@ def member_add_many(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["POST"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.add_member', raise_exception=True) def add_many_confirm(request, *args, **kwargs): models = request.session['models'] @@ -108,7 +113,8 @@ def add_many_confirm(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["POST"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.add_member', raise_exception=True) def member_submit(request, *args, **kwargs): """Add member based on data gained from member form.""" form = MemberForm(request.POST) @@ -128,7 +134,8 @@ def member_submit(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["POST"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.change_member', raise_exception=True) def member_update(request, *args, **kwargs): """Update member information.""" form = MemberForm(request.POST) @@ -154,7 +161,8 @@ def member_update(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["POST"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.delete_member', raise_exception=True) def member_delete(request, *args, **kwargs): """Delete member.""" try: @@ -181,7 +189,8 @@ def member_delete(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.change_member', raise_exception=True) def member_edit(request, *args, **kwargs): """Edit member information.""" i = kwargs.pop('index', None) diff --git a/members/views/payments.py b/members/views/payments.py index b5f22af..4c9a587 100644 --- a/members/views/payments.py +++ b/members/views/payments.py @@ -1,5 +1,5 @@ from django.shortcuts import render -from django.contrib.auth.decorators import permission_required +from django.contrib.auth.decorators import permission_required, login_required from django.views.decorators.http import require_http_methods from django.views.decorators.csrf import ensure_csrf_cookie from django.http import HttpResponse, HttpResponseRedirect @@ -18,7 +18,8 @@ from members.forms import PaymentForm @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.read_payment', raise_exception=True) def payment_list(request, *args, **kwargs): """Render list of payments.""" search = request.GET.get('q', None) @@ -45,7 +46,8 @@ def payment_list(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.add_payment', raise_exception=True) def payment_add(request, *args, **kwargs): """Render add payment form.""" form = PaymentForm() @@ -54,7 +56,8 @@ def payment_add(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["POST"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.add_payment', raise_exception=True) def payment_submit(request, *args, **kwargs): """Submit payment.""" form = PaymentForm(request.POST) @@ -75,7 +78,8 @@ def payment_submit(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.change_payment', raise_exception=True) def payment_edit(request, *args, **kwargs): """Edit payment.""" i = kwargs.pop('index', None) @@ -93,7 +97,8 @@ def payment_edit(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.delete_payment', raise_exception=True) def payment_delete_confirm(request, *args, **kwargs): """Render payment delete confirmation page.""" i = kwargs.pop('index', None) @@ -111,7 +116,8 @@ def payment_delete_confirm(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["POST"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.delete_payment', raise_exception=True) def payment_delete(request, *args, **kwargs): """Delete payment.""" try: @@ -139,7 +145,8 @@ def payment_delete(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["POST"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.change_payment', raise_exception=True) def payment_update(request, *args, **kwargs): """Update payment information.""" form = PaymentForm(request.POST) diff --git a/members/views/utils.py b/members/views/utils.py index 3463914..8d8e7ae 100644 --- a/members/views/utils.py +++ b/members/views/utils.py @@ -1,5 +1,5 @@ from django.shortcuts import render -from django.contrib.auth.decorators import permission_required +from django.contrib.auth.decorators import permission_required, login_required from django.views.decorators.http import require_http_methods from django.views.decorators.csrf import ensure_csrf_cookie from django.http import HttpResponse, HttpResponseRedirect @@ -93,7 +93,8 @@ def convert_table_to_html(table, request): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.change_member', raise_exception=True) def settings_page(request, *args, **kwargs): """Render member app settings page.""" return render(request, 'settings.html', {}) @@ -101,7 +102,8 @@ def settings_page(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["POST"]) -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required(['members.change_member', 'members.change_payment'], raise_exception=True) def import_csv(request, *args, **kwargs): """Get csv data imported to page and create members based on that.""" try: @@ -145,7 +147,7 @@ def import_csv(request, *args, **kwargs): @ensure_csrf_cookie @require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') +@permission_required('members.read_member', login_url='/login', raise_exception=True) def export_csv(request, *args, **kwargs): """Export members as csv.""" response = HttpResponse() diff --git a/requirements.txt b/requirements.txt index 42871fa..8c2804c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,3 +28,4 @@ django-phonenumber-field==1.3.0 paho-mqtt==1.3.0 django-autocomplete-light==3.2.10 six==1.10.0 +django-suit==0.2.25 diff --git a/sikweb/base.py b/sikweb/base.py index 5cdb35a..3b7637f 100644 --- a/sikweb/base.py +++ b/sikweb/base.py @@ -64,6 +64,7 @@ LOGGING = { INSTALLED_APPS = [ 'modeltranslation', # has to be before admin for translation admin to work + 'suit', 'dal', 'dal_select2', 'django.contrib.admin', @@ -249,3 +250,35 @@ STATICFILES_DIRS = ( ) MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/' + +LOGIN_URL = '/login/' +LOGIN_REDIRECT_URL = '/admin' + +SUIT_CONFIG = { + # header + 'ADMIN_NAME': 'SIK Admin', + # 'HEADER_DATE_FORMAT': 'l, j. F Y', + # 'HEADER_TIME_FORMAT': 'H:i', + + # forms + # 'SHOW_REQUIRED_ASTERISK': True, # Default True + # 'CONFIRM_UNSAVED_CHANGES': True, # Default True + + # menu + # 'SEARCH_URL': '/admin/auth/user/', + # 'MENU_ICONS': { + # 'sites': 'icon-leaf', + # 'auth': 'icon-lock', + # }, + # 'MENU_OPEN_FIRST_CHILD': True, # Default True + # 'MENU_EXCLUDE': ('auth.group',), + # 'MENU': ( + # 'sites', + # {'app': 'auth', 'icon':'icon-lock', 'models': ('user', 'group')}, + # {'label': 'Settings', 'icon':'icon-cog', 'models': ('auth.user', 'auth.group')}, + # {'label': 'Support', 'icon':'icon-question-sign', 'url': '/support/'}, + # ), + + # misc + # 'LIST_PER_PAGE': 15 +} diff --git a/static/css/sikadmin.css b/static/css/sikadmin.css new file mode 100644 index 0000000..41aeb61 --- /dev/null +++ b/static/css/sikadmin.css @@ -0,0 +1,17 @@ +body { + font-size: 14px; +} + +.header { + background: #003366; + padding-top: 1rem; + padding-bottom: 1rem; +} + +.header #branding { + border-right: 0px; +} + +.header .header-content.header-content-first { + border-left: 0px; +} diff --git a/templates/admin/base_site.html b/templates/admin/base_site.html new file mode 100644 index 0000000..ee05b40 --- /dev/null +++ b/templates/admin/base_site.html @@ -0,0 +1,74 @@ +{% extends "admin/base.html" %} +{% load admin_static %} + +{% load i18n %} +{# Additional content here, some extra meta tags or favicon #} +{#{% block extrahead %}#} +{#{% endblock %}#} + + +{# Additional CSS includes #} +{% block extrastyle %} + +{% endblock %} + + +{# Additional JS files in footer, right before #} +{#{% block extrajs %}#} +{# #} +{#{% endblock %}#} + + +{# Footer links (left side) #} +{#{% block footer_links %}#} +{# Documentation#} +{#{% endblock %}#} + +{# Additional header content like notifications or language switcher #} +{% block header_content %} + {{ block.super }} +
+
{% csrf_token %} + + + +
+ + +
+{% endblock %} + +{# Footer branding name (center) #} +{#{% block footer_branding %}#} +{#{% endblock %}#} + + +{# Footer copyright (right side) #} +{#{% block copyright %}#} +{# Copyright © 2013 Client
Developed by YourName #} +{#{% endblock %}#} diff --git a/webapp/admin.py b/webapp/admin.py index 03faf69..59a0086 100644 --- a/webapp/admin.py +++ b/webapp/admin.py @@ -2,17 +2,20 @@ from django.contrib import admin from webapp.models import Official, Role -from webapp.models import Feed, Tag, BaseFeed, Event +from webapp.models import Feed, Tag, BaseFeed, Event, Registration from webapp.models import KaehmyForm, KaehmyMessage from webapp.models import CustomKaehmyRole, PresetKaehmyRole from modeltranslation.admin import TranslationAdmin - +from django.contrib.auth.models import Permission # this is needed so that the models get registered for translation import webapp.translation +admin.site.register(Permission) + admin.site.register(Feed, TranslationAdmin) admin.site.register(Tag, TranslationAdmin) admin.site.register(Event, TranslationAdmin) +admin.site.register(Registration, TranslationAdmin) admin.site.register(Official) admin.site.register(Role) admin.site.register(KaehmyForm) diff --git a/webapp/management/commands/initialize.py b/webapp/management/commands/initialize.py index 650a175..31073e3 100644 --- a/webapp/management/commands/initialize.py +++ b/webapp/management/commands/initialize.py @@ -9,31 +9,59 @@ class Command(BaseCommand): This command MUST do nothing if already run. ''' + def create_infoscreen_moderator(self): + self.stdout.write("Creating infoscreen moderator group") + infoscreen_group, created = Group.objects.get_or_create(name="infoscreen moderators") + if not created: + self.stdout.write('The group "infoscreen moderators" already existed ' + 'and was not therefore created') + + cts = ContentType.objects.filter(app_label='infoscreen') + permissions = Permission.objects.filter(content_type__in=cts) + infoscreen_group.permissions.add(*permissions) + + def create_member_register_viewer(self): + self.stdout.write("Creating member register viewer group") + viewers_group, created = Group.objects.get_or_create(name="member register viewers") + if not created: + self.stdout.write('The group "member register viewers" already existed ' + 'and was not therefore created') + + cts = ContentType.objects.filter(app_label='members') + members_permissions = Permission.objects.filter(content_type__in=cts, codename__contains='read') + + viewers_group.permissions.add(*members_permissions) + + def create_member_register_administrator(self): + self.stdout.write("Creating member register administrator group") + admins_group, created = Group.objects.get_or_create(name="member register administrators") + if not created: + self.stdout.write('The group "member register administrators" already existed ' + 'and was not therefore created') + + cts = ContentType.objects.filter(app_label='members') + permissions = Permission.objects.filter(content_type__in=cts) + admins_group.permissions.add(*permissions) + + def create_official(self): + self.stdout.write("Creating official group") + officials_group, created = Group.objects.get_or_create(name="officials") + if not created: + self.stdout.write('The group "officials" already existed ' + 'and was not therefore created') + + cts = ContentType.objects.filter(app_label='webapp') + feed_permissions = Permission.objects.filter(content_type__in=cts, codename__contains='feed') + event_permissions = Permission.objects.filter(content_type__in=cts, codename__contains='event') + registration_permissions = Permission.objects.filter(content_type__in=cts, codename__contains='registration') + + officials_group.permissions.add(*feed_permissions) + officials_group.permissions.add(*event_permissions) + officials_group.permissions.add(*registration_permissions) + def handle(self, *args, **options): - - self.stdout.write("Creating sikadmin group") - sikadmin_group, created = Group.objects.get_or_create(name="sikadmin") - if not created: - self.stdout.write('The group "sikadmin" already existed' - 'and was not therefore created') - - self.stdout.write("Creating sikadmin permission") - - # TODO Use some sikadmin native model when such exists - group_ctype = ContentType.objects.get_for_model(Group) - sikadmin_permission, created = Permission.objects.get_or_create( - codename='sikadmin', - content_type=group_ctype, - name='SIK Admin') - - if not created: - self.stdout.write('The permission "sikadmin" already existed' - 'and was not therefore created') - - self.stdout.write("Giving sikadmin group permission to sikadmin") - if sikadmin_group.permissions.filter(id=sikadmin_permission.id).exists(): - self.stdout.write("Permission already existed. skipping...") - else: - sikadmin_group.permissions.add(sikadmin_permission) - + self.create_infoscreen_moderator() + self.create_member_register_viewer() + self.create_member_register_administrator() + self.create_official() self.stdout.write("Initialization successful") diff --git a/webapp/migrations/0015_auto_20170928_2331.py b/webapp/migrations/0015_auto_20170928_2331.py new file mode 100644 index 0000000..baaa4bb --- /dev/null +++ b/webapp/migrations/0015_auto_20170928_2331.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-09-28 20:31 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0014_auto_20170920_1807'), + ] + + operations = [ + migrations.AlterModelOptions( + name='event', + options={'verbose_name': 'Event', 'verbose_name_plural': 'Events'}, + ), + migrations.AlterModelOptions( + name='feed', + options={'verbose_name': 'Feed', 'verbose_name_plural': 'Feeds'}, + ), + migrations.AlterModelOptions( + name='registration', + options={'verbose_name': 'Registration', 'verbose_name_plural': 'Registrations'}, + ), + migrations.AlterModelOptions( + name='tag', + options={'verbose_name': 'Tag', 'verbose_name_plural': 'Tags'}, + ), + migrations.AddField( + model_name='registration', + name='name_en', + field=models.CharField(max_length=255, null=True), + ), + migrations.AddField( + model_name='registration', + name='name_fi', + field=models.CharField(max_length=255, null=True), + ), + ] diff --git a/webapp/models.py b/webapp/models.py index 812d9f9..b48add0 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -12,6 +12,9 @@ from phonenumber_field.modelfields import PhoneNumberField from django.contrib.postgres.fields import JSONField +VERBOSE_NAME = _('Webapp') + + class Tag(models.Model): """Model for tag.""" @@ -19,6 +22,13 @@ class Tag(models.Model): name = models.CharField(max_length=127) icon = models.ImageField() + class Meta: + verbose_name = _('Tag') + verbose_name_plural = _('Tags') + + def __str__(self): + return _('Tag: {}').format(self.slug) + class BaseFeed(models.Model): """Model containing something showing on some info feed.""" @@ -36,6 +46,13 @@ class Feed(BaseFeed): publish_time = models.DateTimeField(default=timezone.now) autohide = models.DateTimeField(default=month_from_now) + def __str__(self): + return _('Feed: {}').format(self.title) + + class Meta: + verbose_name = _('Feed') + verbose_name_plural = _('Feeds') + class Event(BaseFeed): """Model for event.""" @@ -45,6 +62,13 @@ class Event(BaseFeed): registration = models.ForeignKey( 'Registration', on_delete=models.CASCADE, null=True) + def __str__(self): + return _('Event: {}').format(self.title) + + class Meta: + verbose_name = _('Event') + verbose_name_plural = _('Events') + class Registration(models.Model): """Model for event registration.""" @@ -53,6 +77,13 @@ class Registration(models.Model): email = models.EmailField() options = JSONField() + def __str__(self): + return _('Registration: {}').format(self.name) + + class Meta: + verbose_name = _('Registration') + verbose_name_plural = _('Registrations') + class BaseRole(models.Model): """Base model for occupations/roles.""" diff --git a/webapp/translation.py b/webapp/translation.py index 9ee016d..36b4cfc 100644 --- a/webapp/translation.py +++ b/webapp/translation.py @@ -1,7 +1,7 @@ """Translation classes.""" from modeltranslation.translator import register, TranslationOptions -from webapp.models import BaseFeed, Feed, Tag, Event +from webapp.models import BaseFeed, Feed, Tag, Event, Registration @register(BaseFeed) @@ -30,3 +30,10 @@ class TagTranslationOptions(TranslationOptions): """Class for tag translation options.""" fields = ('name',) + + +@register(Registration) +class RegistrationTranslationOptions(TranslationOptions): + """Class for registration translation options.""" + + fields = ('name',) diff --git a/webapp/views.py b/webapp/views.py index c8859c7..0c2ea69 100644 --- a/webapp/views.py +++ b/webapp/views.py @@ -5,7 +5,7 @@ from django.contrib.auth import login, logout, authenticate from django.views.decorators.http import require_http_methods from django.views.decorators.csrf import ensure_csrf_cookie from django.http import HttpResponse, HttpResponseRedirect -from django.contrib.auth.decorators import permission_required +from django.contrib.auth.decorators import permission_required, login_required from django.conf import settings import logging from webapp.models import OhlhafvChallenge @@ -21,7 +21,8 @@ def main_index(request, *args, **kwargs): @require_http_methods(["GET", "POST"]) @ensure_csrf_cookie -@permission_required('members.change_member', login_url='/login') +@login_required(login_url='/login') +@permission_required('members.change_member') def admin_index(request, *args, **kwargs): """Render admin main page.""" return render(request, "admin_index.html", {}) @@ -50,7 +51,7 @@ def login_view(request, *args, **kwargs): return render(request, "login.html", {}) -@require_http_methods(["POST"]) +@require_http_methods(["GET", "POST"]) def logout_view(request, *args, **kwargs): """Logout user and return to main page.""" logout(request)