diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..f21739a5 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,10 @@ +[run] +source = + note_kfet + note_theme + note_adherents +omit = + note_theme/tests/*.py + note_theme/migrations/*.py + note_adherents/tests/*.py + note_adherents/migrations/*.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..bceb5f51 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,21 @@ +image: python:3.6 + +stages: + - test + +before_script: + - pip install tox + +python36: + image: python:3.6 + stage: test + script: tox -e py36 + +python37: + image: python:3.7 + stage: test + script: tox -e py37 + +linters: + stage: test + script: tox -e linters diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000..6ddf1f3c --- /dev/null +++ b/.pylintrc @@ -0,0 +1,379 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS,.git + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Use multiple processes to speed up Pylint. +jobs=4 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Allow optimization of some AST trees. This will activate a peephole AST +# optimizer, which will apply various small optimizations. For instance, it can +# be used to obtain the result of joining multiple strings with the addition +# operator. Joining a lot of strings can lead to a maximum recursion error in +# Pylint and this flag can prevent that. It has one side effect, the resulting +# AST will be different than the one from reality. +optimize-ast=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence=INFERENCE_FAILURE + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=intern-builtin,nonzero-method,parameter-unpacking,backtick,raw_input-builtin,dict-view-method,filter-builtin-not-iterating,long-builtin,unichr-builtin,input-builtin,unicode-builtin,file-builtin,map-builtin-not-iterating,delslice-method,apply-builtin,cmp-method,setslice-method,coerce-method,long-suffix,raising-string,import-star-module-level,buffer-builtin,reload-builtin,unpacking-in-except,print-statement,hex-method,old-octal-literal,metaclass-assignment,dict-iter-method,range-builtin-not-iterating,using-cmp-argument,indexing-exception,no-absolute-import,coerce-builtin,getslice-method,suppressed-message,execfile-builtin,round-builtin,useless-suppression,reduce-builtin,old-raise-syntax,zip-builtin-not-iterating,cmp-builtin,xrange-builtin,standarderror-builtin,old-division,oct-method,next-method-called,old-ne-operator,basestring-builtin + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[BASIC] + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=yes + +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for argument names +argument-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for attribute names +attr-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for function names +function-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for method names +method-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for variable names +variable-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[ELIF] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=100 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). This supports can work +# with qualified names. +ignored-classes= + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_$|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=20 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=20 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=10 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of boolean expressions in an if statement +max-bool-expr=5 + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=optparse + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception + diff --git a/note_adherents/__init__.py b/note_adherents/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/note_adherents/models.py b/note_adherents/models.py new file mode 100644 index 00000000..b3034ed4 --- /dev/null +++ b/note_adherents/models.py @@ -0,0 +1,75 @@ +# -*- mode: python; coding: utf-8 -*- +# Copyright (C) 2016-2019 by BDE +# SPDX-License-Identifier: GPL-3.0-or-later + +from django.conf import settings +from django.contrib.auth.models import User +from django.db import models +from django.db.models.signals import post_save +from django.dispatch import receiver +from django.utils.translation import gettext_lazy as _ + + +class Profile(models.Model): + """ + An user profile + + We do not want to patch the Django Contrib Auth User class + so this model add an user profile with additional information. + """ + user = models.OneToOneField( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + ) + phone_number = models.CharField( + max_length=255, + verbose_name=_('phone number'), + ) + section = models.CharField( + max_length=255, + verbose_name=_('section'), + help_text=_('e.g. "1A0", "9A♥", "SAPHIRE"'), + ) + + class Meta: + verbose_name = _('user profile') + verbose_name_plural = _('user profile') + + def __str__(self): + return self.user.get_username() + + +class MembershipFee(models.Model): + """ + TODO + """ + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.PROTECT, + ) + date = models.CharField( + max_length=255, + verbose_name=_('phone number'), + ) + amount = models.CharField( + max_length=255, + verbose_name=_('section'), + help_text=_('e.g. "1A0", "9A♥", "SAPHIRE"'), + ) + + class Meta: + verbose_name = _('user profile') + verbose_name_plural = _('user profile') + + def __str__(self): + return self.user.get_username() + + +@receiver(post_save, sender=User) +def save_user_profile(sender, instance, created, **_kwargs): + """ + Hook to save an user profile when an user is updated + """ + if created: + Profile.objects.create(user=instance) + instance.profile.save() diff --git a/note_adherents/tests/__init__.py b/note_adherents/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/note_theme/__init__.py b/note_theme/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/note_theme/locale/fr/LC_MESSAGES/django.po b/note_theme/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 00000000..0a74fa30 --- /dev/null +++ b/note_theme/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,104 @@ +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-30 16:26+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: templates/admin/base_site.html:22 templates/base.html:48 +msgid "Welcome," +msgstr "" + +#: templates/admin/base_site.html:27 +msgid "View site" +msgstr "Retour au site" + +#: templates/admin/base_site.html:32 templates/admin/base_site.html:51 +#: templates/base.html:52 +msgid "View admin" +msgstr "Administration" + +#: templates/admin/base_site.html:44 +msgid "Documentation" +msgstr "" + +#: templates/admin/base_site.html:53 templates/base.html:56 +msgid "Log out" +msgstr "" + +#: templates/base.html:62 templates/registration/login.html:9 +#: templates/registration/login.html:56 +msgid "Log in" +msgstr "" + +#: templates/registration/logged_out.html:9 +#: templates/registration/password_change_done.html:9 +#: templates/registration/password_change_form.html:9 +#: templates/registration/password_reset_complete.html:9 +#: templates/registration/password_reset_confirm.html:9 +#: templates/registration/password_reset_done.html:9 +#: templates/registration/password_reset_form.html:9 +msgid "Home" +msgstr "" + +#: templates/registration/login.html:14 +msgid "Please correct the error below." +msgstr "" + +#: templates/registration/login.html:15 +msgid "Please correct the errors below." +msgstr "" + +#: templates/registration/login.html:31 +#, python-format +msgid "" +"You are authenticated as %(username)s, but are not authorized to access this " +"page. Would you like to login to a different account?" +msgstr "" + +#: templates/registration/login.html:52 +msgid "Forgotten your password?" +msgstr "Mot de passe oublié ?" + +#: templates/registration/password_change_done.html:9 +#: templates/registration/password_change_form.html:9 +msgid "Password change" +msgstr "" + +#: templates/registration/password_reset_complete.html:9 +#: templates/registration/password_reset_done.html:9 +#: templates/registration/password_reset_form.html:9 +msgid "Password reset" +msgstr "" + +#: templates/registration/password_reset_confirm.html:9 +msgid "Password reset confirmation" +msgstr "" + +#: templates/registration/password_reset_email.html:2 +#, python-format +msgid "" +"You're receiving this email because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" + +#: templates/registration/password_reset_email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "" + +#: templates/registration/password_reset_email.html:9 +msgid "Thanks for using our site!" +msgstr "" + +#: templates/registration/password_reset_email.html:11 +#, python-format +msgid "The %(site_name)s team" +msgstr "" diff --git a/note_theme/static/css/admin.css b/note_theme/static/css/admin.css new file mode 100644 index 00000000..59b09f36 --- /dev/null +++ b/note_theme/static/css/admin.css @@ -0,0 +1,141 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Copyright © 2019 Alexandre Iooss + * + * This is the custom style for Django Contrib Admin + */ + +/* Colors */ +#header { + background-color: #151515; + border-bottom: solid 5px #d80029; + padding: 10px 40px; +} + +.module h2, .module caption, .inline-group h2 { + background: #e6e0d8; + color: #222; +} + +a.section:link, a.section:visited { + color: #222; +} + +#user-tools a { + border-bottom: none; + font-weight: bold; +} + +div.breadcrumbs { + background: #3c3c3c; +} + +.button, input[type=submit], input[type=button], .submit-row input, a.button { + background: #d8a456; +} + +.button:active, input[type=submit]:active, input[type=button]:active, .button:focus, input[type=submit]:focus, +input[type=button]:focus, .button:hover, input[type=submit]:hover, input[type=button]:hover { + background: #b98d4a; +} + +.button.default, input[type=submit].default, .submit-row input.default { + background: #b98d4a; +} + +.button.default:active, input[type=submit].default:active, .button.default:focus, input[type=submit].default:focus, +.button.default:hover, input[type=submit].default:hover { + background: #a7752b; +} + +/* User tools top menu */ +#user-tools .dropdown:hover > a, #user-tools .dropdown:focus > a { + color: #79aec8; +} + +#user-tools .dropdown { + position: relative; /* needed to position the dropdown content */ + display: inline-block; +} + +#user-tools .dropdown-content { + display: block; + position: absolute; + background-color: #444444; + min-width: 180px; + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); + z-index: 2000; + text-align: left; + + /* Hide menu by making it transparent */ + transition: opacity 100ms, visibility 100ms; + opacity: 0; + visibility: hidden; +} + +#user-tools .dropdown-content a { + color: #fff; + padding: 7px 8px; + text-decoration: none; + display: block; + line-height: 16px; +} + +#user-tools .dropdown-content a:hover { + background-color: #636363; +} + +#user-tools .dropdown:hover .dropdown-content { + opacity: 1; + visibility: visible; +} + +/* Fix navigation hidden */ +#header { + overflow: visible; +} + +.login #header { + overflow: hidden; +} + +/* Footer */ +#footer { + padding: 20px 40px; + color: #999; +} + +.login #footer { + padding: 10px; + font-size: 10pt; +} + +#footer a { + color: #777; +} + +#footer select { + height: 24px; + padding: 0; +} + +/* Pull footer to bottom */ +#content { + min-height: calc(100vh - 190px); +} + +.login #content { + min-height: 0; +} + +/* Recenter login button */ +.login .submit-row { + padding: 1em 0 0 0 !important; + text-align: center !important; +} + +/* Dashboard should take all page */ +.dashboard #content { + width: auto; +} diff --git a/note_theme/static/favicon/android-chrome-192x192.png b/note_theme/static/favicon/android-chrome-192x192.png new file mode 100644 index 00000000..5b31f298 Binary files /dev/null and b/note_theme/static/favicon/android-chrome-192x192.png differ diff --git a/note_theme/static/favicon/android-chrome-512x512.png b/note_theme/static/favicon/android-chrome-512x512.png new file mode 100644 index 00000000..bb9e4daa Binary files /dev/null and b/note_theme/static/favicon/android-chrome-512x512.png differ diff --git a/note_theme/static/favicon/apple-touch-icon.png b/note_theme/static/favicon/apple-touch-icon.png new file mode 100644 index 00000000..c0b462bd Binary files /dev/null and b/note_theme/static/favicon/apple-touch-icon.png differ diff --git a/note_theme/static/favicon/browserconfig.xml b/note_theme/static/favicon/browserconfig.xml new file mode 100644 index 00000000..49604f0e --- /dev/null +++ b/note_theme/static/favicon/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/note_theme/static/favicon/favicon-16x16.png b/note_theme/static/favicon/favicon-16x16.png new file mode 100644 index 00000000..5db7ed94 Binary files /dev/null and b/note_theme/static/favicon/favicon-16x16.png differ diff --git a/note_theme/static/favicon/favicon-32x32.png b/note_theme/static/favicon/favicon-32x32.png new file mode 100644 index 00000000..a3d9263f Binary files /dev/null and b/note_theme/static/favicon/favicon-32x32.png differ diff --git a/note_theme/static/favicon/favicon.ico b/note_theme/static/favicon/favicon.ico new file mode 100644 index 00000000..53393cda Binary files /dev/null and b/note_theme/static/favicon/favicon.ico differ diff --git a/note_theme/static/favicon/mstile-150x150.png b/note_theme/static/favicon/mstile-150x150.png new file mode 100644 index 00000000..378274c9 Binary files /dev/null and b/note_theme/static/favicon/mstile-150x150.png differ diff --git a/note_theme/static/favicon/safari-pinned-tab.svg b/note_theme/static/favicon/safari-pinned-tab.svg new file mode 100644 index 00000000..a8425e8a --- /dev/null +++ b/note_theme/static/favicon/safari-pinned-tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/note_theme/static/favicon/site.webmanifest b/note_theme/static/favicon/site.webmanifest new file mode 100644 index 00000000..78fcc75f --- /dev/null +++ b/note_theme/static/favicon/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/static/favicon/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/static/favicon/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/note_theme/templates/admin/base_site.html b/note_theme/templates/admin/base_site.html new file mode 100644 index 00000000..3ef7f8a5 --- /dev/null +++ b/note_theme/templates/admin/base_site.html @@ -0,0 +1,96 @@ +{% extends "admin/base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} + +{% load i18n staticfiles %} + +{% block title %}{{ title }} | {{ request.site.name }}{% endblock %} + +{% block branding %} + + + {{ request.site.name }} + + +{% endblock %} + +{% block usertools %} + {% if user.is_authenticated %} +
+ {% block welcome-msg %} + {% trans 'Welcome,' %} + {% firstof user.get_short_name user.get_username %}. + {% endblock %} + {% block userlinks %} + {% if site_url %} + {% trans 'View site' %} / + {% endif %} + {% if available_apps %} + {# When in admin site, list all admin pages and documentation #} + + {% trans 'View admin' %} + + {% for app in available_apps %} + {% for model in app.models %} + {% if model.admin_url %} + {{ model.name }} + {% endif %} + {% endfor %} + {% endfor %} + {% if user.is_active and user.is_superuser %} + {% url 'django-admindocs-docroot' as docsroot %} + {% if docsroot %} + {% trans 'Documentation' %} + {% endif %} + {% endif %} + + / + {% elif user.is_staff %} + {# When not in admin site, but user is staff then add a link #} + {% trans 'View admin' %} / + {% endif %} + {% trans 'Log out' %} + {% endblock %} +
+ {% endif %} +{% endblock %} + +{% block extrastyle %} + + + {# Favicon #} + + + + + + + + + +{% endblock %} + +{% block footer %} + {% if not is_popup %} + + {% endif %} +{% endblock %} diff --git a/note_theme/templates/registration/logged_out.html b/note_theme/templates/registration/logged_out.html new file mode 100644 index 00000000..3ecc65e2 --- /dev/null +++ b/note_theme/templates/registration/logged_out.html @@ -0,0 +1,11 @@ +{% extends "registration/logged_out.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_change_done.html b/note_theme/templates/registration/password_change_done.html new file mode 100644 index 00000000..d42fbfd9 --- /dev/null +++ b/note_theme/templates/registration/password_change_done.html @@ -0,0 +1,11 @@ +{% extends "registration/password_change_done.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_change_form.html b/note_theme/templates/registration/password_change_form.html new file mode 100644 index 00000000..07ab38c9 --- /dev/null +++ b/note_theme/templates/registration/password_change_form.html @@ -0,0 +1,11 @@ +{% extends "registration/password_change_form.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_reset_complete.html b/note_theme/templates/registration/password_reset_complete.html new file mode 100644 index 00000000..f0ec4b8f --- /dev/null +++ b/note_theme/templates/registration/password_reset_complete.html @@ -0,0 +1,11 @@ +{% extends "registration/password_reset_complete.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_reset_confirm.html b/note_theme/templates/registration/password_reset_confirm.html new file mode 100644 index 00000000..62a761d5 --- /dev/null +++ b/note_theme/templates/registration/password_reset_confirm.html @@ -0,0 +1,11 @@ +{% extends "registration/password_reset_confirm.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_reset_done.html b/note_theme/templates/registration/password_reset_done.html new file mode 100644 index 00000000..ea67e596 --- /dev/null +++ b/note_theme/templates/registration/password_reset_done.html @@ -0,0 +1,11 @@ +{% extends "registration/password_reset_done.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_reset_email.html b/note_theme/templates/registration/password_reset_email.html new file mode 100644 index 00000000..f43d80c3 --- /dev/null +++ b/note_theme/templates/registration/password_reset_email.html @@ -0,0 +1,13 @@ +{% load i18n %}{% autoescape off %} +{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %} + +{% trans "Please go to the following page and choose a new password:" %} +{% block reset_link %} +{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} +{% endblock %} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} + +{% endautoescape %} diff --git a/note_theme/templates/registration/password_reset_form.html b/note_theme/templates/registration/password_reset_form.html new file mode 100644 index 00000000..865d5160 --- /dev/null +++ b/note_theme/templates/registration/password_reset_form.html @@ -0,0 +1,11 @@ +{% extends "registration/password_reset_form.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/tests/__init__.py b/note_theme/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/note_theme/tests/test_templates.py b/note_theme/tests/test_templates.py new file mode 100644 index 00000000..6d00c147 --- /dev/null +++ b/note_theme/tests/test_templates.py @@ -0,0 +1,44 @@ +# -*- mode: python; coding: utf-8 -*- +# SPDX-License-Identifier: GPL-3.0-or-later + +from django.contrib.auth.models import User +from django.test import TestCase + +""" +Test that every themed page still works +""" + + +class TemplateLoggedOutTests(TestCase): + def test_login_page(self): + response = self.client.get('/admin/login/') + self.assertEqual(response.status_code, 200) + + +class TemplateLoggedInTests(TestCase): + def setUp(self): + self.user = User.objects.create_superuser( + username="admin", + password="adminadmin", + email="admin@example.com", + ) + self.client.force_login(self.user) + + def test_login_page(self): + """ + Login page should redirect + """ + response = self.client.get('/admin/login/') + self.assertEqual(response.status_code, 302) + + def test_admin_index(self): + response = self.client.get('/admin/') + self.assertEqual(response.status_code, 200) + + def test_accounts_password_reset(self): + response = self.client.get('/accounts/password_reset/') + self.assertEqual(response.status_code, 200) + + def test_logout_page(self): + response = self.client.get('/accounts/logout/') + self.assertEqual(response.status_code, 200) diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..615a2701 --- /dev/null +++ b/tox.ini @@ -0,0 +1,49 @@ +[tox] +envlist = py36,py37,linters +skipsdist = True + +[testenv] +basepython = python3 +deps = + -r{toxinidir}/requirements.txt + coverage +commands = + coverage run ./manage.py test {posargs} + coverage report -m + +[testenv:pre-commit] +deps = pre-commit +commands = + pre-commit run --all-files --show-diff-on-failure + +[testenv:linters] +deps = + -r{toxinidir}/requirements.txt + flake8 + flake8-colors + flake8-import-order + flake8-typing-imports + pep8-naming + pyflakes + pylint +commands = + flake8 note_* + pylint . + +[flake8] +ignore = D203, W503, E203 +exclude = + .tox, + .git, + __pycache__, + build, + dist, + *.pyc, + *.egg-info, + .cache, + .eggs +max-complexity = 10 +import-order-style = google +application-import-names = flake8 +format = ${cyan}%(path)s${reset}:${yellow_bold}%(row)d${reset}:${green_bold}%(col)d${reset}: ${red_bold}%(code)s${reset} %(text)s +