diff --git a/olapp/core/apps.py b/olapp/core/apps.py index 26f78a8e673340121f68a92930e2830bc58d269d..5ef1d600da3500626bfb855e8d489c82aeb6670f 100644 --- a/olapp/core/apps.py +++ b/olapp/core/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class CoreConfig(AppConfig): - name = 'core' + name = "core" diff --git a/olapp/core/forms.py b/olapp/core/forms.py index c64d11e5160d0b9082e3c818fe467f9d099d1d3b..541ab94705ae2854941519a9159138db7387515c 100644 --- a/olapp/core/forms.py +++ b/olapp/core/forms.py @@ -4,8 +4,8 @@ from django import forms from .sanitizers import extract_text, strip_all_tags -INPUT_CLASS = 'form-control form-control-sm' -ERROR_CLASS = 'is-invalid' +INPUT_CLASS = "form-control form-control-sm" +ERROR_CLASS = "is-invalid" class ErrorClassMixin: @@ -17,87 +17,85 @@ class ErrorClassMixin: def is_valid(self): valid = super(ErrorClassMixin, self).is_valid() for f in self.errors: - self.fields[f].widget.attrs.update({ - 'class': self.fields[f].widget.attrs.get('class', '') + ' ' + ERROR_CLASS, - }) + self.fields[f].widget.attrs.update( + { + "class": self.fields[f].widget.attrs.get("class", "") + + " " + + ERROR_CLASS + } + ) return valid class SearchForm(forms.Form): - q = forms.CharField(label='Query', required=False) + q = forms.CharField(label="Query", required=False) def clean_q(self): - return extract_text(self.cleaned_data['q']) + return extract_text(self.cleaned_data["q"]) class LoginForm(ErrorClassMixin, forms.Form): openid_uid = forms.CharField( - label='OpenID', - help_text='Váš unikátní OpenID identifikátor, např.: uzivatel@mojeid.cz', + label="OpenID", + help_text="Váš unikátní OpenID identifikátor, např.: uzivatel@mojeid.cz", required=True, - widget=forms.TextInput(attrs={'class': INPUT_CLASS}), + widget=forms.TextInput(attrs={"class": INPUT_CLASS}), ) class ReportForm(ErrorClassMixin, forms.Form): - id = forms.CharField( - label='id', - required=False, - widget=forms.HiddenInput(), - ) + id = forms.CharField(label="id", required=False, widget=forms.HiddenInput()) title = forms.CharField( - label='titulek', - widget=forms.TextInput(attrs={'class': INPUT_CLASS}), + label="titulek", widget=forms.TextInput(attrs={"class": INPUT_CLASS}) ) body = forms.CharField( - label='report', - widget=forms.Textarea(attrs={'class': INPUT_CLASS}), + label="report", widget=forms.Textarea(attrs={"class": INPUT_CLASS}) ) received_benefit = forms.CharField( - label='přijaté výhody', + label="přijaté výhody", required=False, - widget=forms.TextInput(attrs={'class': INPUT_CLASS}), + widget=forms.TextInput(attrs={"class": INPUT_CLASS}), ) provided_benefit = forms.CharField( - label='poskytnuté výhody', + label="poskytnuté výhody", required=False, - widget=forms.TextInput(attrs={'class': INPUT_CLASS}), + widget=forms.TextInput(attrs={"class": INPUT_CLASS}), ) date = forms.DateField( - label='datum kontaktu', + label="datum kontaktu", initial=date.today, - widget=forms.DateInput(attrs={'class': INPUT_CLASS + ' col-md-2'}), + widget=forms.DateInput(attrs={"class": INPUT_CLASS + " col-md-2"}), ) our_participants = forms.CharField( - label='naši účastníci', + label="naši účastníci", required=False, - widget=forms.TextInput(attrs={'class': INPUT_CLASS}), + widget=forms.TextInput(attrs={"class": INPUT_CLASS}), ) other_participants = forms.CharField( - label='ostatní účastníci', + label="ostatní účastníci", required=False, - widget=forms.TextInput(attrs={'class': INPUT_CLASS}), + widget=forms.TextInput(attrs={"class": INPUT_CLASS}), ) def clean(self): cleaned_data = super().clean() - cleaned_data['is_draft'] = 'publish' not in self.data + cleaned_data["is_draft"] = "publish" not in self.data return cleaned_data def clean_title(self): - return strip_all_tags(self.cleaned_data['title']) + return strip_all_tags(self.cleaned_data["title"]) def clean_body(self): - return strip_all_tags(self.cleaned_data['body']) + return strip_all_tags(self.cleaned_data["body"]) def clean_received_benefit(self): - return strip_all_tags(self.cleaned_data['received_benefit']) + return strip_all_tags(self.cleaned_data["received_benefit"]) def clean_provided_benefit(self): - return strip_all_tags(self.cleaned_data['provided_benefit']) + return strip_all_tags(self.cleaned_data["provided_benefit"]) def clean_our_participants(self): - return strip_all_tags(self.cleaned_data['our_participants']) + return strip_all_tags(self.cleaned_data["our_participants"]) def clean_other_participants(self): - return strip_all_tags(self.cleaned_data['other_participants']) + return strip_all_tags(self.cleaned_data["other_participants"]) diff --git a/olapp/core/graphql.py b/olapp/core/graphql.py index cffbd99bf489608c5449b8bf58f9989756bda9d4..d69e3862f73ee50934e2d495aa812569e8feffb2 100644 --- a/olapp/core/graphql.py +++ b/olapp/core/graphql.py @@ -36,23 +36,23 @@ class NotFoundError(Exception): def decode_global_id(global_id): - return base64.b64decode(global_id).decode('utf-8').split(':') + return base64.b64decode(global_id).decode("utf-8").split(":") def encode_global_id(type, id): - global_id = '{}:{}'.format(type, id) - return base64.b64encode(global_id.encode('utf-8')).decode('utf-8') + global_id = "{}:{}".format(type, id) + return base64.b64encode(global_id.encode("utf-8")).decode("utf-8") def encode_cursor(num): - return base64.b64encode(str(num).encode('utf-8')).decode('utf-8') + return base64.b64encode(str(num).encode("utf-8")).decode("utf-8") def pythonize_user(user): - type, id = decode_global_id(user['id']) - user['id'] = id - if user['extra'] is not None: - user['extra'] = json.loads(user['extra']) + type, id = decode_global_id(user["id"]) + user["id"] = id + if user["extra"] is not None: + user["extra"] = json.loads(user["extra"]) return user @@ -61,21 +61,23 @@ def pythonize_author(author): def pythonize_report(report): - type, id = decode_global_id(report['id']) - report['id'] = id - if 'extra' in report and report['extra'] is not None: - report['extra'] = json.loads(report['extra']) - if 'date' in report: - report['date'] = arrow.get(report['date']).to(settings.TIME_ZONE).date() - if 'published' in report: - report['published'] = arrow.get(report['published']).to(settings.TIME_ZONE).datetime - if 'author' in report and report['author'] is not None: - report['author'] = pythonize_author(report['author']) + type, id = decode_global_id(report["id"]) + report["id"] = id + if "extra" in report and report["extra"] is not None: + report["extra"] = json.loads(report["extra"]) + if "date" in report: + report["date"] = arrow.get(report["date"]).to(settings.TIME_ZONE).date() + if "published" in report: + report["published"] = ( + arrow.get(report["published"]).to(settings.TIME_ZONE).datetime + ) + if "author" in report and report["author"] is not None: + report["author"] = pythonize_author(report["author"]) return report def get_viewer_from_data(data): - viewer = data.get('viewer') + viewer = data.get("viewer") if viewer is None: return None return pythonize_user(viewer) @@ -83,11 +85,11 @@ def get_viewer_from_data(data): def call_api(api_url, query, *, variables=None, token=None): if token is not None: - headers = {'Authorization': 'Bearer {}'.format(token)} + headers = {"Authorization": "Bearer {}".format(token)} else: headers = {} - payload = {'query': query, 'variables': variables} + payload = {"query": query, "variables": variables} try: response = requests.post(api_url, json=payload, headers=headers) @@ -100,10 +102,10 @@ def call_api(api_url, query, *, variables=None, token=None): content = response.json() - if 'errors' in content: - raise GraphQLError(content['errors']) + if "errors" in content: + raise GraphQLError(content["errors"]) - return content['data'] + return content["data"] def call_query(api_url, query, *, viewer=VIEWER, variables=None, token=None): @@ -111,7 +113,9 @@ def call_query(api_url, query, *, viewer=VIEWER, variables=None, token=None): query {{ {query} {viewer} -}}""".format(query=query, viewer=viewer) +}}""".format( + query=query, viewer=viewer + ) data = call_api(api_url, query_, variables=variables, token=token) viewer = get_viewer_from_data(data) return data, viewer diff --git a/olapp/core/middleware.py b/olapp/core/middleware.py index be2f23f315103c5cd1528f71c36415f26b11a9da..c60b93fb0659fe47a4aa65d79fcc4051a283c513 100644 --- a/olapp/core/middleware.py +++ b/olapp/core/middleware.py @@ -9,7 +9,6 @@ from .utils import UnauthorizedError class CustomErrorResponsesMiddleware: - def __init__(self, get_response): self.get_response = get_response @@ -18,13 +17,13 @@ class CustomErrorResponsesMiddleware: def process_exception(self, request, exception): if isinstance(exception, ServiceUnavailableError): - return HttpResponse(loader.render_to_string('503.html'), status=503) + return HttpResponse(loader.render_to_string("503.html"), status=503) if isinstance(exception, UnauthorizedError): - return redirect('login') + return redirect("login") if isinstance(exception, InvalidTokenError): - response = HttpResponseRedirect(reverse('index')) + response = HttpResponseRedirect(reverse("index")) response.delete_cookie(settings.ACCESS_TOKEN_COOKIE) return response diff --git a/olapp/core/mutations.py b/olapp/core/mutations.py index 3b453c934c2ff16684695bea6df6935269f7bc37..2c35fb0772399c7196ede805bd211941a6ea8fbe 100644 --- a/olapp/core/mutations.py +++ b/olapp/core/mutations.py @@ -8,9 +8,11 @@ def login(api_url, openid_uid, redirect_uri): authorizationUrl }} }} - """.format(openid_uid=openid_uid, redirect_uri=redirect_uri) + """.format( + openid_uid=openid_uid, redirect_uri=redirect_uri + ) data = call_mutation(api_url, mutation) - return data['login'] + return data["login"] def login_by_shortcut(api_url, shortcut_id, redirect_uri): @@ -20,9 +22,11 @@ def login_by_shortcut(api_url, shortcut_id, redirect_uri): authorizationUrl }} }} - """.format(shortcut_id=shortcut_id, redirect_uri=redirect_uri) + """.format( + shortcut_id=shortcut_id, redirect_uri=redirect_uri + ) data = call_mutation(api_url, mutation) - return data['loginByShortcut'] + return data["loginByShortcut"] def logout(api_url, *, token=None): @@ -34,7 +38,7 @@ def logout(api_url, *, token=None): } """ data = call_mutation(api_url, mutation, token=token) - return data['logout']['success'] + return data["logout"]["success"] def create_report(api_url, report, *, token=None): @@ -48,18 +52,18 @@ def create_report(api_url, report, *, token=None): } """ input = { - 'title': report['title'], - 'body': report['body'], - 'receivedBenefit': report['received_benefit'], - 'providedBenefit': report['provided_benefit'], - 'date': report['date'].isoformat(), - 'ourParticipants': report['our_participants'], - 'otherParticipants': report['other_participants'], - 'isDraft': report['is_draft'], + "title": report["title"], + "body": report["body"], + "receivedBenefit": report["received_benefit"], + "providedBenefit": report["provided_benefit"], + "date": report["date"].isoformat(), + "ourParticipants": report["our_participants"], + "otherParticipants": report["other_participants"], + "isDraft": report["is_draft"], } - variables = {'input': input} + variables = {"input": input} data = call_mutation(api_url, mutation, variables=variables, token=token) - type, id = decode_global_id(data['createReport']['report']['id']) + type, id = decode_global_id(data["createReport"]["report"]["id"]) return id @@ -74,17 +78,17 @@ def update_report(api_url, report, *, token=None): } """ input = { - 'id': encode_global_id('Report', report['id']), - 'title': report['title'], - 'body': report['body'], - 'receivedBenefit': report['received_benefit'], - 'providedBenefit': report['provided_benefit'], - 'date': report['date'].isoformat(), - 'ourParticipants': report['our_participants'], - 'otherParticipants': report['other_participants'], - 'isDraft': report['is_draft'], + "id": encode_global_id("Report", report["id"]), + "title": report["title"], + "body": report["body"], + "receivedBenefit": report["received_benefit"], + "providedBenefit": report["provided_benefit"], + "date": report["date"].isoformat(), + "ourParticipants": report["our_participants"], + "otherParticipants": report["other_participants"], + "isDraft": report["is_draft"], } - variables = {'input': input} + variables = {"input": input} data = call_mutation(api_url, mutation, variables=variables, token=token) - type, id = decode_global_id(data['updateReport']['report']['id']) + type, id = decode_global_id(data["updateReport"]["report"]["id"]) return id diff --git a/olapp/core/queries.py b/olapp/core/queries.py index 9f6eedd13b37e0007354db5a05037f6324734002..8ec220ee1cd410865952b30ec8644be189878911 100644 --- a/olapp/core/queries.py +++ b/olapp/core/queries.py @@ -9,10 +9,14 @@ from .graphql import ( def search_reports(api_url, slice, *, token=None): - if 'after' in slice: - slice_info = """(query:"{query}", highlight:true, first:{first}, after:"{after}")""".format(**slice) + if "after" in slice: + slice_info = """(query:"{query}", highlight:true, first:{first}, after:"{after}")""".format( + **slice + ) else: - slice_info = """(query:"{query}", highlight:true, first:{first})""".format(**slice) + slice_info = """(query:"{query}", highlight:true, first:{first})""".format( + **slice + ) query = """ searchReports {slice} {{ @@ -39,12 +43,14 @@ def search_reports(api_url, slice, *, token=None): }} }} }} - """.format(slice=slice_info) + """.format( + slice=slice_info + ) data, viewer = call_query(api_url, query, token=token) - search = data['searchReports'] + search = data["searchReports"] - for edge in search['edges']: - edge['node'] = pythonize_report(edge['node']) + for edge in search["edges"]: + edge["node"] = pythonize_report(edge["node"]) return search, viewer @@ -73,10 +79,12 @@ def get_report(api_url, id, *, token=None): }} }} }} - """.format(id=encode_global_id('Report', id)) + """.format( + id=encode_global_id("Report", id) + ) data, viewer = call_query(api_url, query, token=token) - report = data['node'] + report = data["node"] if report is None: raise NotFoundError() @@ -84,7 +92,7 @@ def get_report(api_url, id, *, token=None): def get_author_with_reports(api_url, id, slice, *, token=None): - if 'after' in slice: + if "after" in slice: slice_info = """(first:{first}, after:"{after}")""".format(**slice) else: slice_info = """(first:{first})""".format(**slice) @@ -116,31 +124,33 @@ def get_author_with_reports(api_url, id, slice, *, token=None): }} }} }} - """.format(id=encode_global_id('Author', id), slice=slice_info) + """.format( + id=encode_global_id("Author", id), slice=slice_info + ) data, viewer = call_query(api_url, query, token=token) - author = data['node'] + author = data["node"] if author is None: raise NotFoundError() author = pythonize_author(author) - for edge in author['reports']['edges']: - edge['node'] = pythonize_report(edge['node']) + for edge in author["reports"]["edges"]: + edge["node"] = pythonize_report(edge["node"]) # extend report with author info - edge['node']['author'] = { - 'id': author['id'], - 'firstName': author['firstName'], - 'lastName': author['lastName'], - 'hasCollidingName': author['hasCollidingName'], - 'extra': author['extra'], + edge["node"]["author"] = { + "id": author["id"], + "firstName": author["firstName"], + "lastName": author["lastName"], + "hasCollidingName": author["hasCollidingName"], + "extra": author["extra"], } return author, viewer def get_viewer(api_url, *, token=None): - data, viewer = call_query(api_url, '', token=token) + data, viewer = call_query(api_url, "", token=token) return viewer @@ -152,15 +162,15 @@ def get_login_shortcuts(api_url, *, token=None): } """ data, viewer = call_query(api_url, query, token=token) - shortcuts = data['loginShortcuts'] + shortcuts = data["loginShortcuts"] for shortcut in shortcuts: - type, id = decode_global_id(shortcut['id']) - shortcut['id'] = id + type, id = decode_global_id(shortcut["id"]) + shortcut["id"] = id return shortcuts, viewer def get_authors(api_url, slice, *, token=None): - if 'after' in slice: + if "after" in slice: slice_info = """(first:{first}, after:"{after}")""".format(**slice) else: slice_info = """(first:{first})""".format(**slice) @@ -179,12 +189,14 @@ def get_authors(api_url, slice, *, token=None): }} }} }} - """.format(slice=slice_info) + """.format( + slice=slice_info + ) data, viewer = call_query(api_url, query, token=token) - authors = data['authors'] + authors = data["authors"] - for edge in authors['edges']: - edge['node'] = pythonize_author(edge['node']) + for edge in authors["edges"]: + edge["node"] = pythonize_author(edge["node"]) return authors, viewer @@ -199,7 +211,7 @@ def get_report_drafts(api_url, *, token=None): } """ data, viewer = call_query(api_url, query, token=token) - drafts = data['reportDrafts'] + drafts = data["reportDrafts"] for draft in drafts: draft = pythonize_report(draft) return drafts, viewer diff --git a/olapp/core/sanitizers.py b/olapp/core/sanitizers.py index 02245afc937c2a32e86fc70fa91e6f1dd01e80e4..9b741a5c9cdab2638a23657f4dda1e1a1dfec07c 100644 --- a/olapp/core/sanitizers.py +++ b/olapp/core/sanitizers.py @@ -8,4 +8,4 @@ def strip_all_tags(value): def extract_text(value): value = strip_all_tags(value) - return ' '.join(re.findall(r'(\b\w+)', value)) + return " ".join(re.findall(r"(\b\w+)", value)) diff --git a/olapp/core/tests/test_graphql.py b/olapp/core/tests/test_graphql.py index 29271f498aac140537a862d41f844028b696d0b6..9c8dcc508e19abc2e8b508c005a63342ff787cc4 100644 --- a/olapp/core/tests/test_graphql.py +++ b/olapp/core/tests/test_graphql.py @@ -1,18 +1,14 @@ -from ..graphql import ( - decode_global_id, - encode_global_id, - encode_cursor, -) +from ..graphql import decode_global_id, encode_global_id, encode_cursor def test_decode_global_id(): # encoded value: User:ABC123 - assert decode_global_id('VXNlcjpBQkMxMjM=') == ['User', 'ABC123'] + assert decode_global_id("VXNlcjpBQkMxMjM=") == ["User", "ABC123"] def test_encode_global_id(): - assert encode_global_id('User', 'ABC123') == 'VXNlcjpBQkMxMjM=' + assert encode_global_id("User", "ABC123") == "VXNlcjpBQkMxMjM=" def test_encode_cursor(): - assert encode_cursor(42) == 'NDI=' + assert encode_cursor(42) == "NDI=" diff --git a/olapp/core/tests/test_sanitizers.py b/olapp/core/tests/test_sanitizers.py index 12061a1ea0d8460f81e5a7968e0ccec6c9ef913b..17b78b17339e837e8b38b84100cb0e17ee01808f 100644 --- a/olapp/core/tests/test_sanitizers.py +++ b/olapp/core/tests/test_sanitizers.py @@ -3,24 +3,30 @@ import pytest from ..sanitizers import strip_all_tags, extract_text -@pytest.mark.parametrize('input, text', [ - ('foo', 'foo'), - ('has multiple words', 'has multiple words'), - ('has <b>some</b> tags', 'has some tags'), - ("<IMG SRC=jAvascript:alert('test2')>", ''), -]) +@pytest.mark.parametrize( + "input, text", + [ + ("foo", "foo"), + ("has multiple words", "has multiple words"), + ("has <b>some</b> tags", "has some tags"), + ("<IMG SRC=jAvascript:alert('test2')>", ""), + ], +) def test_strip_all_tags(input, text): assert strip_all_tags(input) == text -@pytest.mark.parametrize('input, text', [ - ('foo', 'foo'), - ('has multiple words', 'has multiple words'), - ('has <b>some</b> tags', 'has some tags'), - ('x" onload="alert()"', 'x onload alert'), - ("'; drop database; x='y", 'drop database x y'), - ("<IMG SRC=jAvascript:alert('test2')>", ''), - ('=/*-+.', ''), -]) +@pytest.mark.parametrize( + "input, text", + [ + ("foo", "foo"), + ("has multiple words", "has multiple words"), + ("has <b>some</b> tags", "has some tags"), + ('x" onload="alert()"', "x onload alert"), + ("'; drop database; x='y", "drop database x y"), + ("<IMG SRC=jAvascript:alert('test2')>", ""), + ("=/*-+.", ""), + ], +) def test_extract_text(input, text): assert extract_text(input) == text diff --git a/olapp/core/utils.py b/olapp/core/utils.py index 4778d59a68c3ca6d7a3c0a37549635d0cac513fe..93b3a1603e3a2eafcd5d64db2fa52174fe934fed 100644 --- a/olapp/core/utils.py +++ b/olapp/core/utils.py @@ -10,10 +10,12 @@ def get_token(func): """View method decorator which gets token from cookie and passes it in method kwargs. """ + @wraps(func) def inner_func(self, *args, **kwargs): - kwargs['token'] = self.request.COOKIES.get(settings.ACCESS_TOKEN_COOKIE) + kwargs["token"] = self.request.COOKIES.get(settings.ACCESS_TOKEN_COOKIE) return func(self, *args, **kwargs) + return inner_func @@ -21,12 +23,14 @@ def viewer_required(func): """View method decorator which raises UnauthorizedError if logged in viewer is not in context data. """ + @wraps(func) def inner_func(self, *args, **kwargs): context = func(self, *args, **kwargs) - if context.get('viewer') is None: + if context.get("viewer") is None: raise UnauthorizedError() return context + return inner_func @@ -45,7 +49,7 @@ def shorten_pages(page, pages, total_pages): for i in sorted(items): if i - last > 1: out.append(None) - out.append(pages[i-1]) + out.append(pages[i - 1]) last = i return out @@ -55,18 +59,18 @@ def get_page_info(page, pages, total_pages): if page == 1: previous_url = None else: - previous_url = pages[page - 2]['url'] + previous_url = pages[page - 2]["url"] if page == total_pages or total_pages == 0: next_url = None else: - next_url = pages[page]['url'] + next_url = pages[page]["url"] return { - 'show': len(pages) > 1, - 'page': page, - 'pages': shorten_pages(page, pages, total_pages), - 'total_pages': total_pages, - 'previous_url': previous_url, - 'next_url': next_url, + "show": len(pages) > 1, + "page": page, + "pages": shorten_pages(page, pages, total_pages), + "total_pages": total_pages, + "previous_url": previous_url, + "next_url": next_url, } diff --git a/olapp/core/views.py b/olapp/core/views.py index c254bcdface65a588cb98119cd7671fc98199f3d..0389d89da2318420012bca2d4f7cb761c2848ef4 100644 --- a/olapp/core/views.py +++ b/olapp/core/views.py @@ -23,159 +23,167 @@ REPORTS_PER_PAGE = 10 class IndexView(TemplateView): - template_name = 'core/index.html' + template_name = "core/index.html" @get_token def get_context_data(self, token, **kwargs): context = super().get_context_data(**kwargs) - query = '' + query = "" form = SearchForm(self.request.GET) if form.is_valid(): - query = form.cleaned_data['q'] + query = form.cleaned_data["q"] # replace form with new one with cleaned input - form = SearchForm({'q': query}) + form = SearchForm({"q": query}) - context['form'] = form + context["form"] = form try: - page = int(self.request.GET.get('p', 1)) + page = int(self.request.GET.get("p", 1)) except ValueError: raise SuspiciousOperation if page > 1: cursor = graphql.encode_cursor((page - 1) * REPORTS_PER_PAGE) - slice = {'query': query, 'first': REPORTS_PER_PAGE, 'after': cursor} + slice = {"query": query, "first": REPORTS_PER_PAGE, "after": cursor} else: - slice = {'query': query, 'first': REPORTS_PER_PAGE} + slice = {"query": query, "first": REPORTS_PER_PAGE} - search, viewer = queries.search_reports(settings.OPENLOBBY_API_URL, slice, token=token) + search, viewer = queries.search_reports( + settings.OPENLOBBY_API_URL, slice, token=token + ) - context['viewer'] = viewer - context['reports'] = [edge['node'] for edge in search['edges']] - context['total_reports'] = search['totalCount'] + context["viewer"] = viewer + context["reports"] = [edge["node"] for edge in search["edges"]] + context["total_reports"] = search["totalCount"] - total_pages = math.ceil(search['totalCount'] / REPORTS_PER_PAGE) + total_pages = math.ceil(search["totalCount"] / REPORTS_PER_PAGE) if page > total_pages and page != 1: raise Http404 - url = reverse('index') + url = reverse("index") pages = [] for num in range(1, total_pages + 1): - url_qs = urllib.parse.urlencode({'q': query, 'p': num}) - page_url = '{}?{}'.format(url, url_qs) - pages.append({'num': num, 'url': page_url, 'active': page == num}) + url_qs = urllib.parse.urlencode({"q": query, "p": num}) + page_url = "{}?{}".format(url, url_qs) + pages.append({"num": num, "url": page_url, "active": page == num}) - context['page_info'] = get_page_info(page, pages, total_pages) + context["page_info"] = get_page_info(page, pages, total_pages) return context class AuthorsView(TemplateView): - template_name = 'core/authors.html' + template_name = "core/authors.html" @get_token def get_context_data(self, token, **kwargs): context = super().get_context_data(**kwargs) try: - page = int(self.request.GET.get('p', 1)) + page = int(self.request.GET.get("p", 1)) except ValueError: raise SuspiciousOperation if page > 1: cursor = graphql.encode_cursor((page - 1) * AUTHORS_PER_PAGE) - slice = {'first': AUTHORS_PER_PAGE, 'after': cursor} + slice = {"first": AUTHORS_PER_PAGE, "after": cursor} else: - slice = {'first': AUTHORS_PER_PAGE} + slice = {"first": AUTHORS_PER_PAGE} - authors, viewer = queries.get_authors(settings.OPENLOBBY_API_URL, slice, token=token) + authors, viewer = queries.get_authors( + settings.OPENLOBBY_API_URL, slice, token=token + ) - context['viewer'] = viewer - context['authors'] = [edge['node'] for edge in authors['edges']] - context['total_reports'] = authors['totalCount'] + context["viewer"] = viewer + context["authors"] = [edge["node"] for edge in authors["edges"]] + context["total_reports"] = authors["totalCount"] - total_pages = math.ceil(authors['totalCount'] / AUTHORS_PER_PAGE) + total_pages = math.ceil(authors["totalCount"] / AUTHORS_PER_PAGE) if page > total_pages and page != 1: raise Http404 - url = reverse('authors') + url = reverse("authors") pages = [] for num in range(1, total_pages + 1): - url_qs = urllib.parse.urlencode({'p': num}) - page_url = '{}?{}'.format(url, url_qs) - pages.append({'num': num, 'url': page_url, 'active': page == num}) + url_qs = urllib.parse.urlencode({"p": num}) + page_url = "{}?{}".format(url, url_qs) + pages.append({"num": num, "url": page_url, "active": page == num}) - context['page_info'] = get_page_info(page, pages, total_pages) + context["page_info"] = get_page_info(page, pages, total_pages) return context class ReportView(TemplateView): - template_name = 'core/report.html' + template_name = "core/report.html" @get_token def get_context_data(self, token, **kwargs): context = super().get_context_data(**kwargs) - saved = self.request.GET.get('saved') + saved = self.request.GET.get("saved") if saved is not None: - context['saved_message'] = True + context["saved_message"] = True try: - report, viewer = queries.get_report(settings.OPENLOBBY_API_URL, kwargs['id'], token=token) + report, viewer = queries.get_report( + settings.OPENLOBBY_API_URL, kwargs["id"], token=token + ) except queries.NotFoundError: raise Http404 - context['report'] = report - context['viewer'] = viewer + context["report"] = report + context["viewer"] = viewer return context class AuthorView(TemplateView): - template_name = 'core/author.html' + template_name = "core/author.html" @get_token def get_context_data(self, token, **kwargs): context = super().get_context_data(**kwargs) - id = kwargs['id'] + id = kwargs["id"] - page = int(kwargs.get('page', 1)) + page = int(kwargs.get("page", 1)) if page > 1: cursor = graphql.encode_cursor((page - 1) * REPORTS_PER_PAGE) - slice = {'first': REPORTS_PER_PAGE, 'after': cursor} + slice = {"first": REPORTS_PER_PAGE, "after": cursor} else: - slice = {'first': REPORTS_PER_PAGE} + slice = {"first": REPORTS_PER_PAGE} try: - author, viewer = queries.get_author_with_reports(settings.OPENLOBBY_API_URL, id, slice, token=token) + author, viewer = queries.get_author_with_reports( + settings.OPENLOBBY_API_URL, id, slice, token=token + ) except queries.NotFoundError: raise Http404 - context['author'] = author - context['viewer'] = viewer - context['reports'] = [edge['node'] for edge in author['reports']['edges']] - context['total_reports'] = author['reports']['totalCount'] + context["author"] = author + context["viewer"] = viewer + context["reports"] = [edge["node"] for edge in author["reports"]["edges"]] + context["total_reports"] = author["reports"]["totalCount"] - total_pages = math.ceil(author['reports']['totalCount'] / REPORTS_PER_PAGE) + total_pages = math.ceil(author["reports"]["totalCount"] / REPORTS_PER_PAGE) pages = [] for num in range(1, total_pages + 1): if num == 1: - url = reverse('author', kwargs={'id': id}) + url = reverse("author", kwargs={"id": id}) else: - url = reverse('author-page', kwargs={'id': id, 'page': num}) - pages.append({'num': num, 'url': url, 'active': page == num}) + url = reverse("author-page", kwargs={"id": id, "page": num}) + pages.append({"num": num, "url": url, "active": page == num}) - context['page_info'] = get_page_info(page, pages, total_pages) + context["page_info"] = get_page_info(page, pages, total_pages) return context class LoginView(FormView): - template_name = 'core/login.html' + template_name = "core/login.html" form_class = LoginForm def get_success_url(self): @@ -184,129 +192,136 @@ class LoginView(FormView): @get_token def get_context_data(self, token, **kwargs): context = super().get_context_data(**kwargs) - login_shortcuts, viewer = queries.get_login_shortcuts(settings.OPENLOBBY_API_URL, token=token) - context['login_shortcuts'] = login_shortcuts - context['viewer'] = viewer + login_shortcuts, viewer = queries.get_login_shortcuts( + settings.OPENLOBBY_API_URL, token=token + ) + context["login_shortcuts"] = login_shortcuts + context["viewer"] = viewer return context def form_valid(self, form): - openid_uid = form.cleaned_data['openid_uid'] - redirect_uri = urllib.parse.urljoin(settings.APP_URL, reverse('login-redirect')) + openid_uid = form.cleaned_data["openid_uid"] + redirect_uri = urllib.parse.urljoin(settings.APP_URL, reverse("login-redirect")) data = mutations.login(settings.OPENLOBBY_API_URL, openid_uid, redirect_uri) - self.authorization_url = data['authorizationUrl'] + self.authorization_url = data["authorizationUrl"] return super().form_valid(form) class LoginByShortcutView(View): - def get(self, request, **kwargs): - shortcut_id = graphql.encode_global_id('LoginShortcut', kwargs['shortcut_id']) - redirect_uri = urllib.parse.urljoin(settings.APP_URL, reverse('login-redirect')) - data = mutations.login_by_shortcut(settings.OPENLOBBY_API_URL, shortcut_id, redirect_uri) - return redirect(data['authorizationUrl']) + shortcut_id = graphql.encode_global_id("LoginShortcut", kwargs["shortcut_id"]) + redirect_uri = urllib.parse.urljoin(settings.APP_URL, reverse("login-redirect")) + data = mutations.login_by_shortcut( + settings.OPENLOBBY_API_URL, shortcut_id, redirect_uri + ) + return redirect(data["authorizationUrl"]) class LoginRedirectView(View): - def get(self, request): - token = request.GET.get('token') + token = request.GET.get("token") # get cookie max_age from token payload = jwt.decode(token, verify=False) - max_age = payload['exp'] - time.time() + max_age = payload["exp"] - time.time() - response = HttpResponseRedirect(reverse('account')) + response = HttpResponseRedirect(reverse("account")) response.set_cookie(settings.ACCESS_TOKEN_COOKIE, token, max_age=max_age) return response class LogoutView(View): - @get_token def get(self, request, token): # TODO # success = mutations.logout(settings.OPENLOBBY_API_URL, token=token) success = True if success: - response = HttpResponseRedirect(reverse('index')) + response = HttpResponseRedirect(reverse("index")) response.delete_cookie(settings.ACCESS_TOKEN_COOKIE) else: - response = redirect('account') + response = redirect("account") return response class AccountView(TemplateView): - template_name = 'core/account.html' + template_name = "core/account.html" @viewer_required @get_token def get_context_data(self, token, **kwargs): context = super().get_context_data(**kwargs) - context['viewer'] = queries.get_viewer(settings.OPENLOBBY_API_URL, token=token) + context["viewer"] = queries.get_viewer(settings.OPENLOBBY_API_URL, token=token) return context class NewReportView(FormView): - template_name = 'core/new_report.html' + template_name = "core/new_report.html" form_class = ReportForm def get_success_url(self): if self.is_draft: - url = reverse('edit-report', kwargs={'id': self.id}) + url = reverse("edit-report", kwargs={"id": self.id}) else: - url = reverse('report', kwargs={'id': self.id}) - return '{}?saved=true'.format(url) + url = reverse("report", kwargs={"id": self.id}) + return "{}?saved=true".format(url) @get_token def form_valid(self, form, token): - id = mutations.create_report(settings.OPENLOBBY_API_URL, form.cleaned_data, token=token) + id = mutations.create_report( + settings.OPENLOBBY_API_URL, form.cleaned_data, token=token + ) self.id = id - self.is_draft = form.cleaned_data['is_draft'] + self.is_draft = form.cleaned_data["is_draft"] return super().form_valid(form) @viewer_required @get_token def get_context_data(self, token, **kwargs): - drafts, viewer = queries.get_report_drafts(settings.OPENLOBBY_API_URL, token=token) + drafts, viewer = queries.get_report_drafts( + settings.OPENLOBBY_API_URL, token=token + ) self.viewer = viewer context = super().get_context_data(**kwargs) - context['drafts'] = drafts - context['viewer'] = self.viewer + context["drafts"] = drafts + context["viewer"] = self.viewer return context def get_initial(self): data = super().get_initial() - if hasattr(self, 'viewer') and self.viewer is not None: - data['our_participants'] = '{firstName} {lastName}'.format(**self.viewer) + if hasattr(self, "viewer") and self.viewer is not None: + data["our_participants"] = "{firstName} {lastName}".format(**self.viewer) return data class EditReportView(FormView): - template_name = 'core/edit_report.html' + template_name = "core/edit_report.html" form_class = ReportForm def get_success_url(self): if self.is_draft: - url = reverse('edit-report', kwargs={'id': self.id}) + url = reverse("edit-report", kwargs={"id": self.id}) else: - url = reverse('report', kwargs={'id': self.id}) - return '{}?saved=true'.format(url) + url = reverse("report", kwargs={"id": self.id}) + return "{}?saved=true".format(url) @get_token def form_valid(self, form, token): - id = mutations.update_report(settings.OPENLOBBY_API_URL, form.cleaned_data, token=token) + id = mutations.update_report( + settings.OPENLOBBY_API_URL, form.cleaned_data, token=token + ) self.id = id - self.is_draft = form.cleaned_data['is_draft'] + self.is_draft = form.cleaned_data["is_draft"] return super().form_valid(form) @viewer_required @get_token def get_context_data(self, token, **kwargs): - id = self.kwargs['id'] + id = self.kwargs["id"] report, viewer = queries.get_report(settings.OPENLOBBY_API_URL, id, token=token) - if not report['isDraft']: - if report['author']['id'] != viewer['id']: + if not report["isDraft"]: + if report["author"]["id"] != viewer["id"]: raise Http404 self.report = report @@ -314,24 +329,24 @@ class EditReportView(FormView): context = super().get_context_data(**kwargs) - saved = self.request.GET.get('saved') + saved = self.request.GET.get("saved") if saved is not None: - context['saved_message'] = True + context["saved_message"] = True - context['report'] = self.report - context['viewer'] = self.viewer + context["report"] = self.report + context["viewer"] = self.viewer return context def get_initial(self): data = super().get_initial() - if hasattr(self, 'report') and self.report is not None: - data['id'] = self.report['id'] - data['date'] = self.report['date'] - data['published'] = self.report['published'] - data['title'] = self.report['title'] - data['body'] = self.report['body'] - data['received_benefit'] = self.report['receivedBenefit'] - data['provided_benefit'] = self.report['providedBenefit'] - data['our_participants'] = self.report['ourParticipants'] - data['other_participants'] = self.report['otherParticipants'] + if hasattr(self, "report") and self.report is not None: + data["id"] = self.report["id"] + data["date"] = self.report["date"] + data["published"] = self.report["published"] + data["title"] = self.report["title"] + data["body"] = self.report["body"] + data["received_benefit"] = self.report["receivedBenefit"] + data["provided_benefit"] = self.report["providedBenefit"] + data["our_participants"] = self.report["ourParticipants"] + data["other_participants"] = self.report["otherParticipants"] return data diff --git a/olapp/formats/cs/formats.py b/olapp/formats/cs/formats.py index d734742440b3d5c046c817c3d4f65a5cb70dc999..ff441180f9627ec81dbe2d2926d071dac34b024a 100644 --- a/olapp/formats/cs/formats.py +++ b/olapp/formats/cs/formats.py @@ -1,5 +1,5 @@ -DATE_FORMAT = 'j. n. Y' -TIME_FORMAT = 'G:i' -DATETIME_FORMAT = 'j. n. Y G:i' -SHORT_DATE_FORMAT = 'j.n.Y' -SHORT_DATETIME_FORMAT = 'j.n.Y G:i' +DATE_FORMAT = "j. n. Y" +TIME_FORMAT = "G:i" +DATETIME_FORMAT = "j. n. Y G:i" +SHORT_DATE_FORMAT = "j.n.Y" +SHORT_DATETIME_FORMAT = "j.n.Y G:i" diff --git a/olapp/settings.py b/olapp/settings.py index 6cb3c6148b20d3530888275b6cf9723cf8f543c0..0f9c5b6941172e097a620122118b32f8d850bfcd 100644 --- a/olapp/settings.py +++ b/olapp/settings.py @@ -4,17 +4,17 @@ import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = 'DEBUG' in os.environ +DEBUG = "DEBUG" in os.environ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = os.environ.get('SECRET_KEY') +SECRET_KEY = os.environ.get("SECRET_KEY") if not SECRET_KEY: if DEBUG: - SECRET_KEY = 'not-secret-at-all' + SECRET_KEY = "not-secret-at-all" else: - raise RuntimeError('Missing SECRET_KEY environment variable.') + raise RuntimeError("Missing SECRET_KEY environment variable.") -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = ["*"] # Application definition @@ -24,72 +24,61 @@ INSTALLED_APPS = [ # 'django.contrib.auth', # 'django.contrib.contenttypes', # 'django.contrib.sessions', - 'django.contrib.staticfiles', - 'olapp.core', + "django.contrib.staticfiles", + "olapp.core", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', + "django.middleware.security.SecurityMiddleware", # 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", # 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'olapp.core.middleware.CustomErrorResponsesMiddleware', + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "olapp.core.middleware.CustomErrorResponsesMiddleware", ] -ROOT_URLCONF = 'olapp.urls' +ROOT_URLCONF = "olapp.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", # 'django.contrib.auth.context_processors.auth', # 'django.contrib.messages.context_processors.messages', - ], + ] }, - }, + } ] -WSGI_APPLICATION = 'olapp.wsgi.application' +WSGI_APPLICATION = "olapp.wsgi.application" -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': ':memory:', - } -} +DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}} # Password validation AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" }, + {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, + {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, + {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, ] # Internationalization -LANGUAGE_CODE = 'cs' +LANGUAGE_CODE = "cs" -TIME_ZONE = 'Europe/Prague' +TIME_ZONE = "Europe/Prague" USE_I18N = True @@ -97,26 +86,19 @@ USE_L10N = True USE_TZ = True -FORMAT_MODULE_PATH = ('olapp.formats',) +FORMAT_MODULE_PATH = ("olapp.formats",) # Static files (CSS, JavaScript, Images) -STATIC_URL = '/static/' +STATIC_URL = "/static/" LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'handlers': { - 'console': { - 'class': 'logging.StreamHandler', - }, - }, - 'loggers': { - 'django': { - 'handlers': ['console'], - 'level': 'INFO' if DEBUG else 'WARNING', - }, + "version": 1, + "disable_existing_loggers": False, + "handlers": {"console": {"class": "logging.StreamHandler"}}, + "loggers": { + "django": {"handlers": ["console"], "level": "INFO" if DEBUG else "WARNING"} }, } @@ -125,10 +107,10 @@ LOGGING = { # Custom settings # DSN to Open Lobby Server -openlobby_server_dsn = os.environ.get('OPENLOBBY_SERVER_DSN', 'http://localhost:8010') -OPENLOBBY_API_URL = '{}/graphql'.format(openlobby_server_dsn) +openlobby_server_dsn = os.environ.get("OPENLOBBY_SERVER_DSN", "http://localhost:8010") +OPENLOBBY_API_URL = "{}/graphql".format(openlobby_server_dsn) # this application URL (for OpenID authentication redirect) -APP_URL = os.environ.get('APP_URL', 'http://localhost:8020') +APP_URL = os.environ.get("APP_URL", "http://localhost:8020") -ACCESS_TOKEN_COOKIE = 'ol_access_token' +ACCESS_TOKEN_COOKIE = "ol_access_token" diff --git a/olapp/urls.py b/olapp/urls.py index 01da9721a14d7e64cc6a756ee5a7fc65d0a1832b..03b54451e62d67994b1005c950eab23fe27297e9 100644 --- a/olapp/urls.py +++ b/olapp/urls.py @@ -14,16 +14,28 @@ from olapp.core.views import ( ) urlpatterns = [ - url(r'^$', IndexView.as_view(), name='index'), - url(r'^login/$', LoginView.as_view(), name='login'), - url(r'^login/(?P<shortcut_id>[0-9A-Za-z-_]+)/$', LoginByShortcutView.as_view(), name='login-by-shortcut'), - url(r'^login-redirect/$', LoginRedirectView.as_view(), name='login-redirect'), - url(r'^logout/$', LogoutView.as_view(), name='logout'), - url(r'^account/$', AccountView.as_view(), name='account'), - url(r'^new-report/$', NewReportView.as_view(), name='new-report'), - url(r'^report/(?P<id>[0-9A-Za-z-_]+)/$', ReportView.as_view(), name='report'), - url(r'^report/(?P<id>[0-9A-Za-z-_]+)/edit/$', EditReportView.as_view(), name='edit-report'), - url(r'^authors/$', AuthorsView.as_view(), name='authors'), - url(r'^author/(?P<id>[0-9A-Za-z-_]+)/$', AuthorView.as_view(), name='author'), - url(r'^author/(?P<id>[0-9A-Za-z-_]+)/(?P<page>[0-9]+)/$', AuthorView.as_view(), name='author-page'), + url(r"^$", IndexView.as_view(), name="index"), + url(r"^login/$", LoginView.as_view(), name="login"), + url( + r"^login/(?P<shortcut_id>[0-9A-Za-z-_]+)/$", + LoginByShortcutView.as_view(), + name="login-by-shortcut", + ), + url(r"^login-redirect/$", LoginRedirectView.as_view(), name="login-redirect"), + url(r"^logout/$", LogoutView.as_view(), name="logout"), + url(r"^account/$", AccountView.as_view(), name="account"), + url(r"^new-report/$", NewReportView.as_view(), name="new-report"), + url(r"^report/(?P<id>[0-9A-Za-z-_]+)/$", ReportView.as_view(), name="report"), + url( + r"^report/(?P<id>[0-9A-Za-z-_]+)/edit/$", + EditReportView.as_view(), + name="edit-report", + ), + url(r"^authors/$", AuthorsView.as_view(), name="authors"), + url(r"^author/(?P<id>[0-9A-Za-z-_]+)/$", AuthorView.as_view(), name="author"), + url( + r"^author/(?P<id>[0-9A-Za-z-_]+)/(?P<page>[0-9]+)/$", + AuthorView.as_view(), + name="author-page", + ), ] diff --git a/setup.py b/setup.py index 7514322ce1c6454eb94f10ad8ccca4a363d2849f..5a5495e0e3c2d3380951912749d389e513444393 100644 --- a/setup.py +++ b/setup.py @@ -6,37 +6,32 @@ from os import path here = path.abspath(path.dirname(__file__)) # Get the long description from the README file -with open(path.join(here, 'README.md'), encoding='utf-8') as f: +with open(path.join(here, "README.md"), encoding="utf-8") as f: long_description = f.read() setup( - name='openlobby-app', - version='0.1.0', - url='https://github.com/openlobby/openlobby-app', - - author='Jan Bednarik', - author_email='jan.bednarik@gmail.com', - - description='Open Lobby App', + name="openlobby-app", + version="0.1.0", + url="https://github.com/openlobby/openlobby-app", + author="Jan Bednarik", + author_email="jan.bednarik@gmail.com", + description="Open Lobby App", long_description=long_description, - - packages=find_packages(exclude=['tests']), - + packages=find_packages(exclude=["tests"]), # TODO # install_requires=[], # extras_require={ # 'dev': [], # 'test': [], # }, - - license='MIT', + license="MIT", classifiers=[ - 'Development Status :: 4 - Beta', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', + "Development Status :: 4 - Beta", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", ], )