forked from data.coop/membersystem
Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
Víðir Valberg Guðmundsson | a9a88c9290 |
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -5,6 +5,3 @@ db.sqlite3
|
||||||
.pytest_cache
|
.pytest_cache
|
||||||
.idea/
|
.idea/
|
||||||
*.mo
|
*.mo
|
||||||
.env
|
|
||||||
venv/
|
|
||||||
.venv/
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ default_language_version:
|
||||||
exclude: ^.*\b(migrations)\b.*$
|
exclude: ^.*\b(migrations)\b.*$
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.5.0
|
rev: v4.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-ast
|
- id: check-ast
|
||||||
- id: check-merge-conflict
|
- id: check-merge-conflict
|
||||||
|
@ -16,13 +16,14 @@ repos:
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||||
rev: 'v0.1.11'
|
rev: 'v0.0.209'
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args:
|
args:
|
||||||
|
- --force-exclude
|
||||||
- --fix
|
- --fix
|
||||||
- repo: https://github.com/asottile/reorder_python_imports
|
- repo: https://github.com/asottile/reorder_python_imports
|
||||||
rev: v3.12.0
|
rev: v3.9.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: reorder-python-imports
|
- id: reorder-python-imports
|
||||||
args:
|
args:
|
||||||
|
@ -30,31 +31,33 @@ repos:
|
||||||
- --application-directories=.:src
|
- --application-directories=.:src
|
||||||
exclude: migrations/
|
exclude: migrations/
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v3.15.0
|
rev: v3.3.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args:
|
args:
|
||||||
- --py311-plus
|
- --py311-plus
|
||||||
exclude: migrations/
|
exclude: migrations/
|
||||||
- repo: https://github.com/adamchainz/django-upgrade
|
- repo: https://github.com/adamchainz/django-upgrade
|
||||||
rev: 1.15.0
|
rev: 1.12.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: django-upgrade
|
- id: django-upgrade
|
||||||
args:
|
args:
|
||||||
- --target-version=4.1
|
- --target-version=4.1
|
||||||
- repo: https://github.com/asottile/yesqa
|
- repo: https://github.com/asottile/yesqa
|
||||||
rev: v1.5.0
|
rev: v1.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: yesqa
|
- id: yesqa
|
||||||
- repo: https://github.com/asottile/add-trailing-comma
|
- repo: https://github.com/asottile/add-trailing-comma
|
||||||
rev: v3.1.0
|
rev: v2.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: add-trailing-comma
|
- id: add-trailing-comma
|
||||||
|
args:
|
||||||
|
- --py36-plus
|
||||||
- repo: https://github.com/hadialqattan/pycln
|
- repo: https://github.com/hadialqattan/pycln
|
||||||
rev: v2.4.0
|
rev: v2.1.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: pycln
|
- id: pycln
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 23.12.1
|
rev: 22.12.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -1,4 +1,4 @@
|
||||||
DOCKER_COMPOSE = COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker compose
|
DOCKER_COMPOSE = COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 venv/bin/docker-compose
|
||||||
DOCKER_RUN = ${DOCKER_COMPOSE} run -u `id -u`
|
DOCKER_RUN = ${DOCKER_COMPOSE} run -u `id -u`
|
||||||
DOCKER_BUILD = DOCKER_BUILDKIT=1 docker build
|
DOCKER_BUILD = DOCKER_BUILDKIT=1 docker build
|
||||||
DOCKER_CONTAINER_NAME = backend
|
DOCKER_CONTAINER_NAME = backend
|
||||||
|
@ -14,7 +14,7 @@ setup_venv:
|
||||||
rm -rf venv
|
rm -rf venv
|
||||||
python3.11 -m venv venv;
|
python3.11 -m venv venv;
|
||||||
venv/bin/python -m pip install wheel setuptools;
|
venv/bin/python -m pip install wheel setuptools;
|
||||||
venv/bin/python -m pip install pre-commit boto3 pip-tools;
|
venv/bin/python -m pip install docker-compose pre-commit boto3 pip-tools;
|
||||||
|
|
||||||
pre_commit_install:
|
pre_commit_install:
|
||||||
venv/bin/pre-commit install
|
venv/bin/pre-commit install
|
||||||
|
|
40
README.md
40
README.md
|
@ -1,22 +1,12 @@
|
||||||
# member.data.coop
|
# member.data.coop
|
||||||
|
|
||||||
## Development
|
## Development requirements
|
||||||
|
|
||||||
### Setup environment
|
|
||||||
|
|
||||||
Copy over the .env.example file to .env and adjust DATABASE_URL accordingly
|
|
||||||
|
|
||||||
$ cp .env.example .env
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
|
|
||||||
#### Requirements
|
|
||||||
|
|
||||||
- Docker
|
- Docker
|
||||||
- Docker compose
|
- Docker compose
|
||||||
- pre-commit (preferred for contributions)
|
- pre-commit (preferred for contributions)
|
||||||
|
|
||||||
#### Setup
|
## Start local server
|
||||||
|
|
||||||
Given that the requirements above are installed, it should be as easy as:
|
Given that the requirements above are installed, it should be as easy as:
|
||||||
|
|
||||||
|
@ -43,29 +33,3 @@ Make messages:
|
||||||
Running tests:
|
Running tests:
|
||||||
|
|
||||||
$ make test
|
$ make test
|
||||||
|
|
||||||
### Non-docker
|
|
||||||
|
|
||||||
Create a venv
|
|
||||||
|
|
||||||
$ python3 -m venv venv
|
|
||||||
|
|
||||||
Activate the venv
|
|
||||||
|
|
||||||
$ source venv/bin/activate
|
|
||||||
|
|
||||||
Install requirements
|
|
||||||
|
|
||||||
$ pip install -r requirements/dev.txt
|
|
||||||
|
|
||||||
Run migrations
|
|
||||||
|
|
||||||
$ ./src/manage.py migrate
|
|
||||||
|
|
||||||
Create a superuser
|
|
||||||
|
|
||||||
$ ./src/manage.py createsuperuser
|
|
||||||
|
|
||||||
Run the server
|
|
||||||
|
|
||||||
$ ./src/manage.py runserver
|
|
||||||
|
|
|
@ -14,8 +14,9 @@ services:
|
||||||
- ./:/app/
|
- ./:/app/
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
- postgres
|
||||||
|
- keycloak
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- env
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:13-alpine
|
image: postgres:13-alpine
|
||||||
|
@ -24,7 +25,27 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- env
|
||||||
|
|
||||||
|
keycloak_db:
|
||||||
|
image: postgres:13-alpine
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data/
|
||||||
|
env_file:
|
||||||
|
- env
|
||||||
|
|
||||||
|
keycloak:
|
||||||
|
image: "quay.io/keycloak/keycloak:20.0"
|
||||||
|
restart: "unless-stopped"
|
||||||
|
command:
|
||||||
|
- "start-dev"
|
||||||
|
- "--db=postgres"
|
||||||
|
- "--db-url=jdbc:postgresql://keycloak_db:5432/postgres"
|
||||||
|
- "--db-username=postgres"
|
||||||
|
- "--db-password=postgres"
|
||||||
|
- "--hostname=localhost"
|
||||||
|
- "--http-relative-path=/auth"
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
|
|
|
@ -3,7 +3,5 @@ POSTGRES_HOST=postgres
|
||||||
POSTGRES_PASSWORD=postgres
|
POSTGRES_PASSWORD=postgres
|
||||||
POSTGRES_PORT=5432
|
POSTGRES_PORT=5432
|
||||||
DATABASE_URL=postgres://postgres:postgres@postgres:5432/postgres
|
DATABASE_URL=postgres://postgres:postgres@postgres:5432/postgres
|
||||||
# Use something along the the following if you are not using docker
|
|
||||||
# DATABASE_URL=postgres://postgres:postgres@localhost:5432/datacoop_membersystem
|
|
||||||
DEBUG=True
|
DEBUG=True
|
||||||
DJANGO_ENV=development
|
DJANGO_ENV=development
|
105
pyproject.toml
105
pyproject.toml
|
@ -1,105 +0,0 @@
|
||||||
[build-system]
|
|
||||||
requires = ["hatchling", "hatch-vcs"]
|
|
||||||
build-backend = "hatchling.build"
|
|
||||||
|
|
||||||
[project]
|
|
||||||
name = "membersystem"
|
|
||||||
description = ''
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.11"
|
|
||||||
keywords = []
|
|
||||||
authors = [
|
|
||||||
{ name = "Víðir Valberg Guðmundsson", email = "valberg@orn.li" },
|
|
||||||
]
|
|
||||||
dependencies = [
|
|
||||||
"Django==5.0.1",
|
|
||||||
"django-money==3.4.1",
|
|
||||||
"django-allauth==0.60.0",
|
|
||||||
"psycopg[binary]==3.1.16",
|
|
||||||
"environs[django]==10.0.0",
|
|
||||||
"uvicorn==0.25.0",
|
|
||||||
"whitenoise==6.6.0",
|
|
||||||
"django-zen-queries==2.1.0",
|
|
||||||
"django-registries==0.0.3",
|
|
||||||
]
|
|
||||||
dynamic = ["version"]
|
|
||||||
|
|
||||||
[tool.hatch.version]
|
|
||||||
source = "vcs"
|
|
||||||
|
|
||||||
[tool.hatch.envs.default]
|
|
||||||
dependencies = [
|
|
||||||
"coverage[toml]==7.3.0",
|
|
||||||
"pytest==7.2.2",
|
|
||||||
"pytest-cov",
|
|
||||||
"pytest-django==4.5.2",
|
|
||||||
"mypy==1.1.1",
|
|
||||||
"django-stubs==1.16.0",
|
|
||||||
"pip-tools==7.3.0",
|
|
||||||
"django-debug-toolbar==4.2.0",
|
|
||||||
"django-browser-reload==1.7.0",
|
|
||||||
"model-bakery==1.17.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[tool.hatch.envs.tests.matrix]]
|
|
||||||
python = ["3.12"]
|
|
||||||
django = ["4.2", "5.0"]
|
|
||||||
|
|
||||||
[tool.hatch.envs.tests.overrides]
|
|
||||||
matrix.django.dependencies = [
|
|
||||||
{ value = "django~={matrix:django}" },
|
|
||||||
]
|
|
||||||
matrix.python.dependencies = [
|
|
||||||
{ value = "typing_extensions==4.5.0", if = ["3.10"]},
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.hatch.envs.default.scripts]
|
|
||||||
cov = "pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=src --cov=tests --cov=append {args}"
|
|
||||||
no-cov = "cov --no-cov {args}"
|
|
||||||
typecheck = "mypy --config-file=pyproject.toml ."
|
|
||||||
requirements = "pip-compile --output-file requirements/base.txt pyproject.toml"
|
|
||||||
server = "./src/manage.py runserver"
|
|
||||||
migrate = "./src/manage.py migrate"
|
|
||||||
makemigrations = "./src/manage.py makemigrations"
|
|
||||||
createsuperuser = "./src/manage.py createsuperuser"
|
|
||||||
shell = "./src/manage.py shell"
|
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
|
||||||
DJANGO_SETTINGS_MODULE="tests.settings"
|
|
||||||
addopts = "--reuse-db"
|
|
||||||
norecursedirs = "build dist docs .eggs/* *.egg-info htmlcov .git"
|
|
||||||
python_files = "test*.py"
|
|
||||||
testpaths = "tests"
|
|
||||||
pythonpath = ". tests"
|
|
||||||
|
|
||||||
[tool.coverage.run]
|
|
||||||
branch = true
|
|
||||||
parallel = true
|
|
||||||
|
|
||||||
[tool.coverage.report]
|
|
||||||
exclude_lines = [
|
|
||||||
"no cov",
|
|
||||||
"if __name__ == .__main__.:",
|
|
||||||
"if TYPE_CHECKING:",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.mypy]
|
|
||||||
mypy_path = "src/"
|
|
||||||
exclude = [
|
|
||||||
"venv/",
|
|
||||||
"dist/",
|
|
||||||
"docs/",
|
|
||||||
]
|
|
||||||
namespace_packages = false
|
|
||||||
show_error_codes = true
|
|
||||||
strict = true
|
|
||||||
warn_unreachable = true
|
|
||||||
follow_imports = "normal"
|
|
||||||
#plugins = ["mypy_django_plugin.main"]
|
|
||||||
|
|
||||||
[tool.django-stubs]
|
|
||||||
#django_settings_module = "tests.settings"
|
|
||||||
|
|
||||||
[[tool.mypy.overrides]]
|
|
||||||
module = "tests.*"
|
|
||||||
allow_untyped_defs = true
|
|
|
@ -1,8 +1,8 @@
|
||||||
Django==5.0.1
|
Django==4.1.5
|
||||||
django-money==3.4.1
|
django-money==1.3
|
||||||
django-allauth==0.60.0
|
django-allauth==0.46
|
||||||
psycopg[binary]==3.1.16
|
psycopg2-binary==2.9.5
|
||||||
environs[django]==10.0.0
|
environs[django]==9.3
|
||||||
uvicorn==0.25.0
|
uvicorn==0.13
|
||||||
whitenoise==6.6.0
|
whitenoise==5.2
|
||||||
django-zen-queries==2.1.0
|
django-zen-queries==2.1.0
|
||||||
|
|
|
@ -1,98 +1,82 @@
|
||||||
#
|
#
|
||||||
# This file is autogenerated by pip-compile with Python 3.11
|
# This file is autogenerated by pip-compile with Python 3.10
|
||||||
# by the following command:
|
# by the following command:
|
||||||
#
|
#
|
||||||
# pip-compile --output-file=requirements/base.txt pyproject.toml
|
# pip-compile --output-file=requirements/base.txt requirements/base.in
|
||||||
#
|
#
|
||||||
asgiref==3.7.2
|
asgiref==3.5.2
|
||||||
# via django
|
# via django
|
||||||
babel==2.14.0
|
certifi==2022.9.24
|
||||||
# via py-moneyed
|
|
||||||
certifi==2023.11.17
|
|
||||||
# via requests
|
# via requests
|
||||||
cffi==1.16.0
|
cffi==1.15.1
|
||||||
# via cryptography
|
# via cryptography
|
||||||
charset-normalizer==3.3.2
|
charset-normalizer==2.1.1
|
||||||
# via requests
|
# via requests
|
||||||
click==8.1.7
|
click==7.1.2
|
||||||
# via uvicorn
|
# via uvicorn
|
||||||
cryptography==41.0.7
|
cryptography==38.0.3
|
||||||
# via pyjwt
|
# via pyjwt
|
||||||
defusedxml==0.7.1
|
defusedxml==0.7.1
|
||||||
# via python3-openid
|
# via python3-openid
|
||||||
dj-database-url==2.1.0
|
dj-database-url==1.0.0
|
||||||
# via environs
|
# via environs
|
||||||
dj-email-url==1.0.6
|
dj-email-url==1.0.6
|
||||||
# via environs
|
# via environs
|
||||||
django==5.0.1
|
django==4.1.5
|
||||||
# via
|
# via
|
||||||
|
# -r requirements/base.in
|
||||||
# dj-database-url
|
# dj-database-url
|
||||||
# django-allauth
|
# django-allauth
|
||||||
# django-money
|
# django-money
|
||||||
# django-registries
|
|
||||||
# django-zen-queries
|
# django-zen-queries
|
||||||
# membersystem (pyproject.toml)
|
django-allauth==0.46
|
||||||
django-allauth==0.60.0
|
# via -r requirements/base.in
|
||||||
# via membersystem (pyproject.toml)
|
django-cache-url==3.4.2
|
||||||
django-cache-url==3.4.5
|
|
||||||
# via environs
|
# via environs
|
||||||
django-money==3.4.1
|
django-money==1.3
|
||||||
# via membersystem (pyproject.toml)
|
# via -r requirements/base.in
|
||||||
django-registries==0.0.3
|
|
||||||
# via membersystem (pyproject.toml)
|
|
||||||
django-zen-queries==2.1.0
|
django-zen-queries==2.1.0
|
||||||
# via membersystem (pyproject.toml)
|
# via -r requirements/base.in
|
||||||
environs[django]==10.0.0
|
environs[django]==9.3
|
||||||
# via
|
# via -r requirements/base.in
|
||||||
# environs
|
|
||||||
# membersystem (pyproject.toml)
|
|
||||||
h11==0.14.0
|
h11==0.14.0
|
||||||
# via uvicorn
|
# via uvicorn
|
||||||
idna==3.6
|
idna==3.4
|
||||||
# via requests
|
# via requests
|
||||||
marshmallow==3.20.1
|
marshmallow==3.19.0
|
||||||
# via environs
|
# via environs
|
||||||
oauthlib==3.2.2
|
oauthlib==3.2.2
|
||||||
# via requests-oauthlib
|
# via requests-oauthlib
|
||||||
packaging==23.2
|
packaging==21.3
|
||||||
# via marshmallow
|
# via marshmallow
|
||||||
psycopg[binary]==3.1.16
|
psycopg2-binary==2.9.5
|
||||||
# via
|
# via -r requirements/base.in
|
||||||
# membersystem (pyproject.toml)
|
py-moneyed==0.8.0
|
||||||
# psycopg
|
|
||||||
psycopg-binary==3.1.16
|
|
||||||
# via psycopg
|
|
||||||
py-moneyed==3.0
|
|
||||||
# via django-money
|
# via django-money
|
||||||
pycparser==2.21
|
pycparser==2.21
|
||||||
# via cffi
|
# via cffi
|
||||||
pyjwt[crypto]==2.8.0
|
pyjwt[crypto]==2.6.0
|
||||||
# via
|
# via django-allauth
|
||||||
# django-allauth
|
pyparsing==3.0.9
|
||||||
# pyjwt
|
# via packaging
|
||||||
python-dotenv==1.0.0
|
python-dotenv==0.21.0
|
||||||
# via environs
|
# via environs
|
||||||
python3-openid==3.2.0
|
python3-openid==3.2.0
|
||||||
# via django-allauth
|
# via django-allauth
|
||||||
requests==2.31.0
|
requests==2.28.1
|
||||||
# via
|
# via
|
||||||
# django-allauth
|
# django-allauth
|
||||||
# requests-oauthlib
|
# requests-oauthlib
|
||||||
requests-oauthlib==1.3.1
|
requests-oauthlib==1.3.1
|
||||||
# via django-allauth
|
# via django-allauth
|
||||||
sqlparse==0.4.4
|
sqlparse==0.4.3
|
||||||
# via django
|
# via django
|
||||||
typing-extensions==4.9.0
|
urllib3==1.26.12
|
||||||
# via
|
|
||||||
# dj-database-url
|
|
||||||
# psycopg
|
|
||||||
# py-moneyed
|
|
||||||
urllib3==2.1.0
|
|
||||||
# via requests
|
# via requests
|
||||||
uvicorn==0.25.0
|
uvicorn==0.13
|
||||||
# via membersystem (pyproject.toml)
|
# via -r requirements/base.in
|
||||||
whitenoise==6.6.0
|
whitenoise==5.2
|
||||||
# via membersystem (pyproject.toml)
|
# via -r requirements/base.in
|
||||||
|
|
||||||
# The following packages are considered to be unsafe in a requirements file:
|
# The following packages are considered to be unsafe in a requirements file:
|
||||||
# setuptools
|
# setuptools
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
-r test.txt
|
-r test.txt
|
||||||
|
|
||||||
django-browser-reload==1.12.1
|
django-browser-reload==1.6.0
|
||||||
django-debug-toolbar==4.2.0
|
django-debug-toolbar==3.7.0
|
||||||
django-extensions==3.2.3
|
django-extensions==3.2.1
|
||||||
django-stubs==4.2.7
|
django-stubs==1.12.0
|
||||||
ipython==8.19.0
|
ipython==8.6.0
|
||||||
mypy==1.8.0
|
mypy==0.990
|
||||||
|
|
|
@ -1,39 +1,36 @@
|
||||||
#
|
#
|
||||||
# This file is autogenerated by pip-compile with Python 3.11
|
# This file is autogenerated by pip-compile with Python 3.10
|
||||||
# by the following command:
|
# by the following command:
|
||||||
#
|
#
|
||||||
# pip-compile --output-file=requirements/dev.txt requirements/dev.in
|
# pip-compile --output-file=requirements/dev.txt requirements/dev.in
|
||||||
#
|
#
|
||||||
asgiref==3.7.2
|
asgiref==3.5.2
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# django
|
# django
|
||||||
# django-browser-reload
|
asttokens==2.1.0
|
||||||
asttokens==2.4.1
|
|
||||||
# via stack-data
|
# via stack-data
|
||||||
babel==2.14.0
|
backcall==0.2.0
|
||||||
# via
|
# via ipython
|
||||||
# -r requirements/test.txt
|
certifi==2022.9.24
|
||||||
# py-moneyed
|
|
||||||
certifi==2023.11.17
|
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# requests
|
# requests
|
||||||
cffi==1.16.0
|
cffi==1.15.1
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# cryptography
|
# cryptography
|
||||||
charset-normalizer==3.3.2
|
charset-normalizer==2.1.1
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# requests
|
# requests
|
||||||
click==8.1.7
|
click==7.1.2
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# uvicorn
|
# uvicorn
|
||||||
coverage==7.4.0
|
coverage==6.5.0
|
||||||
# via -r requirements/test.txt
|
# via -r requirements/test.txt
|
||||||
cryptography==41.0.7
|
cryptography==38.0.3
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# pyjwt
|
# pyjwt
|
||||||
|
@ -43,7 +40,7 @@ defusedxml==0.7.1
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# python3-openid
|
# python3-openid
|
||||||
dj-database-url==2.1.0
|
dj-database-url==1.0.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# environs
|
# environs
|
||||||
|
@ -51,7 +48,7 @@ dj-email-url==1.0.6
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# environs
|
# environs
|
||||||
django==5.0.1
|
django==4.1.5
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# dj-database-url
|
# dj-database-url
|
||||||
|
@ -63,81 +60,81 @@ django==5.0.1
|
||||||
# django-stubs
|
# django-stubs
|
||||||
# django-stubs-ext
|
# django-stubs-ext
|
||||||
# django-zen-queries
|
# django-zen-queries
|
||||||
django-allauth==0.60.0
|
django-allauth==0.46
|
||||||
# via -r requirements/test.txt
|
# via -r requirements/test.txt
|
||||||
django-browser-reload==1.12.1
|
django-browser-reload==1.6.0
|
||||||
# via -r requirements/dev.in
|
# via -r requirements/dev.in
|
||||||
django-cache-url==3.4.5
|
django-cache-url==3.4.2
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# environs
|
# environs
|
||||||
django-debug-toolbar==4.2.0
|
django-debug-toolbar==3.7.0
|
||||||
# via -r requirements/dev.in
|
# via -r requirements/dev.in
|
||||||
django-extensions==3.2.3
|
django-extensions==3.2.1
|
||||||
# via -r requirements/dev.in
|
# via -r requirements/dev.in
|
||||||
django-money==3.4.1
|
django-money==1.3
|
||||||
# via -r requirements/test.txt
|
# via -r requirements/test.txt
|
||||||
django-stubs==4.2.7
|
django-stubs==1.12.0
|
||||||
# via -r requirements/dev.in
|
# via -r requirements/dev.in
|
||||||
django-stubs-ext==4.2.7
|
django-stubs-ext==0.7.0
|
||||||
# via django-stubs
|
# via django-stubs
|
||||||
django-zen-queries==2.1.0
|
django-zen-queries==2.1.0
|
||||||
# via -r requirements/test.txt
|
# via -r requirements/test.txt
|
||||||
environs[django]==10.0.0
|
environs[django]==9.3
|
||||||
# via -r requirements/test.txt
|
# via -r requirements/test.txt
|
||||||
executing==2.0.1
|
executing==1.2.0
|
||||||
# via stack-data
|
# via stack-data
|
||||||
h11==0.14.0
|
h11==0.14.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# uvicorn
|
# uvicorn
|
||||||
idna==3.6
|
idna==3.4
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# requests
|
# requests
|
||||||
ipython==8.19.0
|
ipython==8.6.0
|
||||||
# via -r requirements/dev.in
|
# via -r requirements/dev.in
|
||||||
jedi==0.19.1
|
jedi==0.18.1
|
||||||
# via ipython
|
# via ipython
|
||||||
lxml==5.0.1
|
lxml==4.9.1
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# unittest-xml-reporting
|
# unittest-xml-reporting
|
||||||
marshmallow==3.20.1
|
marshmallow==3.19.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# environs
|
# environs
|
||||||
matplotlib-inline==0.1.6
|
matplotlib-inline==0.1.6
|
||||||
# via ipython
|
# via ipython
|
||||||
mypy==1.8.0
|
mypy==0.990
|
||||||
# via -r requirements/dev.in
|
# via
|
||||||
mypy-extensions==1.0.0
|
# -r requirements/dev.in
|
||||||
|
# django-stubs
|
||||||
|
mypy-extensions==0.4.3
|
||||||
# via mypy
|
# via mypy
|
||||||
oauthlib==3.2.2
|
oauthlib==3.2.2
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# requests-oauthlib
|
# requests-oauthlib
|
||||||
packaging==23.2
|
packaging==21.3
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# marshmallow
|
# marshmallow
|
||||||
parso==0.8.3
|
parso==0.8.3
|
||||||
# via jedi
|
# via jedi
|
||||||
pexpect==4.9.0
|
pexpect==4.8.0
|
||||||
# via ipython
|
# via ipython
|
||||||
prompt-toolkit==3.0.43
|
pickleshare==0.7.5
|
||||||
# via ipython
|
# via ipython
|
||||||
psycopg[binary]==3.1.16
|
prompt-toolkit==3.0.32
|
||||||
|
# via ipython
|
||||||
|
psycopg2-binary==2.9.5
|
||||||
# via -r requirements/test.txt
|
# via -r requirements/test.txt
|
||||||
psycopg-binary==3.1.16
|
|
||||||
# via
|
|
||||||
# -r requirements/test.txt
|
|
||||||
# psycopg
|
|
||||||
ptyprocess==0.7.0
|
ptyprocess==0.7.0
|
||||||
# via pexpect
|
# via pexpect
|
||||||
pure-eval==0.2.2
|
pure-eval==0.2.2
|
||||||
# via stack-data
|
# via stack-data
|
||||||
py-moneyed==3.0
|
py-moneyed==0.8.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# django-money
|
# django-money
|
||||||
|
@ -145,13 +142,17 @@ pycparser==2.21
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# cffi
|
# cffi
|
||||||
pygments==2.17.2
|
pygments==2.13.0
|
||||||
# via ipython
|
# via ipython
|
||||||
pyjwt[crypto]==2.8.0
|
pyjwt[crypto]==2.6.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# django-allauth
|
# django-allauth
|
||||||
python-dotenv==1.0.0
|
pyparsing==3.0.9
|
||||||
|
# via
|
||||||
|
# -r requirements/test.txt
|
||||||
|
# packaging
|
||||||
|
python-dotenv==0.21.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# environs
|
# environs
|
||||||
|
@ -159,7 +160,7 @@ python3-openid==3.2.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# django-allauth
|
# django-allauth
|
||||||
requests==2.31.0
|
requests==2.28.1
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# django-allauth
|
# django-allauth
|
||||||
|
@ -170,43 +171,43 @@ requests-oauthlib==1.3.1
|
||||||
# django-allauth
|
# django-allauth
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
# via asttokens
|
# via asttokens
|
||||||
sqlparse==0.4.4
|
sqlparse==0.4.3
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# django
|
# django
|
||||||
# django-debug-toolbar
|
# django-debug-toolbar
|
||||||
stack-data==0.6.3
|
stack-data==0.6.1
|
||||||
# via ipython
|
# via ipython
|
||||||
tblib==3.0.0
|
tblib==1.7.0
|
||||||
# via -r requirements/test.txt
|
# via -r requirements/test.txt
|
||||||
traitlets==5.14.1
|
tomli==2.0.1
|
||||||
|
# via
|
||||||
|
# django-stubs
|
||||||
|
# mypy
|
||||||
|
traitlets==5.5.0
|
||||||
# via
|
# via
|
||||||
# ipython
|
# ipython
|
||||||
# matplotlib-inline
|
# matplotlib-inline
|
||||||
types-pytz==2023.3.1.1
|
types-pytz==2022.6.0.1
|
||||||
# via django-stubs
|
# via django-stubs
|
||||||
types-pyyaml==6.0.12.12
|
types-pyyaml==6.0.12.2
|
||||||
# via django-stubs
|
# via django-stubs
|
||||||
typing-extensions==4.9.0
|
typing-extensions==4.4.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
|
||||||
# dj-database-url
|
|
||||||
# django-stubs
|
# django-stubs
|
||||||
# django-stubs-ext
|
# django-stubs-ext
|
||||||
# mypy
|
# mypy
|
||||||
# psycopg
|
|
||||||
# py-moneyed
|
|
||||||
unittest-xml-reporting==3.2.0
|
unittest-xml-reporting==3.2.0
|
||||||
# via -r requirements/test.txt
|
# via -r requirements/test.txt
|
||||||
urllib3==2.1.0
|
urllib3==1.26.12
|
||||||
# via
|
# via
|
||||||
# -r requirements/test.txt
|
# -r requirements/test.txt
|
||||||
# requests
|
# requests
|
||||||
uvicorn==0.25.0
|
uvicorn==0.13
|
||||||
# via -r requirements/test.txt
|
# via -r requirements/test.txt
|
||||||
wcwidth==0.2.13
|
wcwidth==0.2.5
|
||||||
# via prompt-toolkit
|
# via prompt-toolkit
|
||||||
whitenoise==6.6.0
|
whitenoise==5.2
|
||||||
# via -r requirements/test.txt
|
# via -r requirements/test.txt
|
||||||
|
|
||||||
# The following packages are considered to be unsafe in a requirements file:
|
# The following packages are considered to be unsafe in a requirements file:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
-r base.txt
|
-r base.txt
|
||||||
|
|
||||||
coverage==7.4.0
|
coverage==6.5.0
|
||||||
tblib==3.0.0
|
tblib==1.7.0
|
||||||
unittest-xml-reporting==3.2.0
|
unittest-xml-reporting==3.2.0
|
||||||
|
|
|
@ -1,36 +1,32 @@
|
||||||
#
|
#
|
||||||
# This file is autogenerated by pip-compile with Python 3.11
|
# This file is autogenerated by pip-compile with Python 3.10
|
||||||
# by the following command:
|
# by the following command:
|
||||||
#
|
#
|
||||||
# pip-compile --output-file=requirements/test.txt requirements/test.in
|
# pip-compile --output-file=requirements/test.txt requirements/test.in
|
||||||
#
|
#
|
||||||
asgiref==3.7.2
|
asgiref==3.5.2
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# django
|
# django
|
||||||
babel==2.14.0
|
certifi==2022.9.24
|
||||||
# via
|
|
||||||
# -r requirements/base.txt
|
|
||||||
# py-moneyed
|
|
||||||
certifi==2023.11.17
|
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# requests
|
# requests
|
||||||
cffi==1.16.0
|
cffi==1.15.1
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# cryptography
|
# cryptography
|
||||||
charset-normalizer==3.3.2
|
charset-normalizer==2.1.1
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# requests
|
# requests
|
||||||
click==8.1.7
|
click==7.1.2
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# uvicorn
|
# uvicorn
|
||||||
coverage==7.4.0
|
coverage==6.5.0
|
||||||
# via -r requirements/test.in
|
# via -r requirements/test.in
|
||||||
cryptography==41.0.7
|
cryptography==38.0.3
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# pyjwt
|
# pyjwt
|
||||||
|
@ -38,7 +34,7 @@ defusedxml==0.7.1
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# python3-openid
|
# python3-openid
|
||||||
dj-database-url==2.1.0
|
dj-database-url==1.0.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# environs
|
# environs
|
||||||
|
@ -46,36 +42,36 @@ dj-email-url==1.0.6
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# environs
|
# environs
|
||||||
django==5.0.1
|
django==4.1.5
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# dj-database-url
|
# dj-database-url
|
||||||
# django-allauth
|
# django-allauth
|
||||||
# django-money
|
# django-money
|
||||||
# django-zen-queries
|
# django-zen-queries
|
||||||
django-allauth==0.60.0
|
django-allauth==0.46
|
||||||
# via -r requirements/base.txt
|
# via -r requirements/base.txt
|
||||||
django-cache-url==3.4.5
|
django-cache-url==3.4.2
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# environs
|
# environs
|
||||||
django-money==3.4.1
|
django-money==1.3
|
||||||
# via -r requirements/base.txt
|
# via -r requirements/base.txt
|
||||||
django-zen-queries==2.1.0
|
django-zen-queries==2.1.0
|
||||||
# via -r requirements/base.txt
|
# via -r requirements/base.txt
|
||||||
environs[django]==10.0.0
|
environs[django]==9.3
|
||||||
# via -r requirements/base.txt
|
# via -r requirements/base.txt
|
||||||
h11==0.14.0
|
h11==0.14.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# uvicorn
|
# uvicorn
|
||||||
idna==3.6
|
idna==3.4
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# requests
|
# requests
|
||||||
lxml==5.0.1
|
lxml==4.9.1
|
||||||
# via unittest-xml-reporting
|
# via unittest-xml-reporting
|
||||||
marshmallow==3.20.1
|
marshmallow==3.19.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# environs
|
# environs
|
||||||
|
@ -83,17 +79,13 @@ oauthlib==3.2.2
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# requests-oauthlib
|
# requests-oauthlib
|
||||||
packaging==23.2
|
packaging==21.3
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# marshmallow
|
# marshmallow
|
||||||
psycopg[binary]==3.1.16
|
psycopg2-binary==2.9.5
|
||||||
# via -r requirements/base.txt
|
# via -r requirements/base.txt
|
||||||
psycopg-binary==3.1.16
|
py-moneyed==0.8.0
|
||||||
# via
|
|
||||||
# -r requirements/base.txt
|
|
||||||
# psycopg
|
|
||||||
py-moneyed==3.0
|
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# django-money
|
# django-money
|
||||||
|
@ -101,11 +93,15 @@ pycparser==2.21
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# cffi
|
# cffi
|
||||||
pyjwt[crypto]==2.8.0
|
pyjwt[crypto]==2.6.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# django-allauth
|
# django-allauth
|
||||||
python-dotenv==1.0.0
|
pyparsing==3.0.9
|
||||||
|
# via
|
||||||
|
# -r requirements/base.txt
|
||||||
|
# packaging
|
||||||
|
python-dotenv==0.21.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# environs
|
# environs
|
||||||
|
@ -113,7 +109,7 @@ python3-openid==3.2.0
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# django-allauth
|
# django-allauth
|
||||||
requests==2.31.0
|
requests==2.28.1
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# django-allauth
|
# django-allauth
|
||||||
|
@ -122,27 +118,21 @@ requests-oauthlib==1.3.1
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# django-allauth
|
# django-allauth
|
||||||
sqlparse==0.4.4
|
sqlparse==0.4.3
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# django
|
# django
|
||||||
tblib==3.0.0
|
tblib==1.7.0
|
||||||
# via -r requirements/test.in
|
# via -r requirements/test.in
|
||||||
typing-extensions==4.9.0
|
|
||||||
# via
|
|
||||||
# -r requirements/base.txt
|
|
||||||
# dj-database-url
|
|
||||||
# psycopg
|
|
||||||
# py-moneyed
|
|
||||||
unittest-xml-reporting==3.2.0
|
unittest-xml-reporting==3.2.0
|
||||||
# via -r requirements/test.in
|
# via -r requirements/test.in
|
||||||
urllib3==2.1.0
|
urllib3==1.26.12
|
||||||
# via
|
# via
|
||||||
# -r requirements/base.txt
|
# -r requirements/base.txt
|
||||||
# requests
|
# requests
|
||||||
uvicorn==0.25.0
|
uvicorn==0.13
|
||||||
# via -r requirements/base.txt
|
# via -r requirements/base.txt
|
||||||
whitenoise==6.6.0
|
whitenoise==5.2
|
||||||
# via -r requirements/base.txt
|
# via -r requirements/base.txt
|
||||||
|
|
||||||
# The following packages are considered to be unsafe in a requirements file:
|
# The following packages are considered to be unsafe in a requirements file:
|
||||||
|
|
|
@ -6,6 +6,7 @@ from . import models
|
||||||
|
|
||||||
@admin.register(models.Order)
|
@admin.register(models.Order)
|
||||||
class OrderAdmin(admin.ModelAdmin):
|
class OrderAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
list_display = ("who", "description", "created", "is_paid")
|
list_display = ("who", "description", "created", "is_paid")
|
||||||
|
|
||||||
@admin.display(description=_("Customer"))
|
@admin.display(description=_("Customer"))
|
||||||
|
@ -15,6 +16,7 @@ class OrderAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
@admin.register(models.Payment)
|
@admin.register(models.Payment)
|
||||||
class PaymentAdmin(admin.ModelAdmin):
|
class PaymentAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
list_display = ("who", "description", "order_id", "created")
|
list_display = ("who", "description", "order_id", "created")
|
||||||
|
|
||||||
@admin.display(description=_("Customer"))
|
@admin.display(description=_("Customer"))
|
||||||
|
|
|
@ -9,6 +9,7 @@ from djmoney.models.fields import MoneyField
|
||||||
|
|
||||||
|
|
||||||
class CreatedModifiedAbstract(models.Model):
|
class CreatedModifiedAbstract(models.Model):
|
||||||
|
|
||||||
modified = models.DateTimeField(auto_now=True, verbose_name=_("modified"))
|
modified = models.DateTimeField(auto_now=True, verbose_name=_("modified"))
|
||||||
created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
|
created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
|
||||||
|
|
||||||
|
@ -96,6 +97,7 @@ class Order(CreatedModifiedAbstract):
|
||||||
|
|
||||||
|
|
||||||
class Payment(CreatedModifiedAbstract):
|
class Payment(CreatedModifiedAbstract):
|
||||||
|
|
||||||
amount = MoneyField(max_digits=16, decimal_places=2)
|
amount = MoneyField(max_digits=16, decimal_places=2)
|
||||||
order = models.ForeignKey(Order, on_delete=models.PROTECT)
|
order = models.ForeignKey(Order, on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
# Generated by Django 4.1.5 on 2023-09-16 14:09
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('auth', '0012_alter_user_first_name_max_length'),
|
|
||||||
('membership', '0004_alter_membership_period'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Member',
|
|
||||||
fields=[
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'proxy': True,
|
|
||||||
'indexes': [],
|
|
||||||
'constraints': [],
|
|
||||||
},
|
|
||||||
bases=('auth.user',),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -12,18 +12,13 @@ from utils.mixins import CreatedModifiedAbstract
|
||||||
class Member(User):
|
class Member(User):
|
||||||
class QuerySet(models.QuerySet):
|
class QuerySet(models.QuerySet):
|
||||||
def annotate_membership(self):
|
def annotate_membership(self):
|
||||||
from .selectors import get_current_subscription_period
|
from membership.selectors import get_current_subscription_period
|
||||||
|
|
||||||
current_subscription_period = get_current_subscription_period()
|
|
||||||
|
|
||||||
if not current_subscription_period:
|
|
||||||
raise ValueError("No current subscription period found")
|
|
||||||
|
|
||||||
return self.annotate(
|
return self.annotate(
|
||||||
active_membership=models.Exists(
|
active_membership=models.Exists(
|
||||||
Membership.objects.filter(
|
Membership.objects.filter(
|
||||||
user=models.OuterRef("pk"),
|
user=models.OuterRef("pk"),
|
||||||
period=current_subscription_period.id,
|
period=get_current_subscription_period().id,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -27,6 +27,7 @@ class Permission:
|
||||||
return f"{self.app_label}.{self.codename}"
|
return f"{self.app_label}.{self.codename}"
|
||||||
|
|
||||||
def persist_permission(self):
|
def persist_permission(self):
|
||||||
|
|
||||||
content_type, _ = ContentType.objects.get_or_create(
|
content_type, _ = ContentType.objects.get_or_create(
|
||||||
app_label=self.app_label,
|
app_label=self.app_label,
|
||||||
model=self.model,
|
model=self.model,
|
||||||
|
|
|
@ -23,7 +23,7 @@ def get_subscription_periods(member: Member | None = None) -> list[SubscriptionP
|
||||||
period=OuterRef("pk"),
|
period=OuterRef("pk"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).filter(membership_exists=True)
|
)
|
||||||
|
|
||||||
return list(subscription_periods)
|
return list(subscription_periods)
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block head_title %}
|
|
||||||
{% trans "Member detail" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="content-view">
|
|
||||||
<h1>
|
<h1>
|
||||||
{{ member.username }}
|
{{ member.username }}
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -16,7 +12,6 @@
|
||||||
|
|
||||||
<h3>{% trans "Membership" %}</h3>
|
<h3>{% trans "Membership" %}</h3>
|
||||||
|
|
||||||
{% if subscription_periods %}
|
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -37,9 +32,8 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% else %}
|
|
||||||
{% trans "No memberships" %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,14 +1,8 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block head_title %}
|
|
||||||
{% trans "Membership" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="content-view">
|
|
||||||
<h2>Membership settings</h2>
|
|
||||||
{% if not current_membership %}
|
{% if not current_membership %}
|
||||||
<p>{% trans "You do not have an active membership!" %}</p>
|
<p>{% trans "You do not have an active membership!" %}</p>
|
||||||
|
|
||||||
|
@ -26,38 +20,4 @@
|
||||||
<p>{% trans "Period" %}: {{ current_period.lower|date:"SHORT_DATE_FORMAT" }} to {{ current_period.upper|date:"SHORT_DATE_FORMAT"|default:next_general_assembly }}</p>
|
<p>{% trans "Period" %}: {{ current_period.lower|date:"SHORT_DATE_FORMAT" }} to {{ current_period.upper|date:"SHORT_DATE_FORMAT"|default:next_general_assembly }}</p>
|
||||||
<p>{% trans "Type" %}: {{ current_membership.membership_type }}</p>
|
<p>{% trans "Type" %}: {{ current_membership.membership_type }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
{% endblock %}
|
||||||
|
|
||||||
<div class="content-view">
|
|
||||||
<h2>Profile settings</h2>
|
|
||||||
<form>
|
|
||||||
<div>
|
|
||||||
<label for="username">
|
|
||||||
Username
|
|
||||||
</label>
|
|
||||||
<input id="username" type="text" value="{{user}}" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="first_name">
|
|
||||||
First name
|
|
||||||
</label>
|
|
||||||
<input id="first_name" type="text" value="{{user.first_name}}" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="last_name">
|
|
||||||
Last name
|
|
||||||
</label>
|
|
||||||
<input id="last_name" type="text" value="{{user.last_name}}" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button>Update Profile</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="view-list">
|
|
||||||
<h2>Email settings</h2>
|
|
||||||
<button>Update Email</button>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.decorators import permission_required
|
from django.contrib.auth.decorators import permission_required
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from zen_queries import render
|
||||||
|
|
||||||
from .permissions import ADMINISTRATE_MEMBERS
|
from .permissions import ADMINISTRATE_MEMBERS
|
||||||
from .selectors import get_member
|
from .selectors import get_member
|
||||||
from .selectors import get_members
|
from .selectors import get_members
|
||||||
from .selectors import get_memberships
|
from .selectors import get_memberships
|
||||||
from .selectors import get_subscription_periods
|
from .selectors import get_subscription_periods
|
||||||
from utils.view_utils import render
|
|
||||||
from utils.view_utils import render_list
|
from utils.view_utils import render_list
|
||||||
from utils.view_utils import RowAction
|
from utils.view_utils import RowAction
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def membership_overview(request):
|
def membership_overview(request):
|
||||||
memberships = get_memberships(member=request.user)
|
memberships = get_memberships(user=request.user)
|
||||||
current_membership = memberships.current()
|
current_membership = memberships.current()
|
||||||
previous_memberships = memberships.previous()
|
previous_memberships = memberships.previous()
|
||||||
|
|
||||||
|
@ -39,8 +39,6 @@ def members_admin(request):
|
||||||
users = get_members()
|
users = get_members()
|
||||||
|
|
||||||
return render_list(
|
return render_list(
|
||||||
entity_name="member",
|
|
||||||
entity_name_plural="members",
|
|
||||||
request=request,
|
request=request,
|
||||||
paginate_by=20,
|
paginate_by=20,
|
||||||
objects=users,
|
objects=users,
|
||||||
|
@ -70,7 +68,6 @@ def members_admin_detail(request, member_id):
|
||||||
context = {
|
context = {
|
||||||
"member": member,
|
"member": member,
|
||||||
"subscription_periods": subscription_periods,
|
"subscription_periods": subscription_periods,
|
||||||
"base_path": "admin-members",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
|
|
5
src/project/context_processors.py
Normal file
5
src/project/context_processors.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
|
|
||||||
|
|
||||||
|
def current_site(request):
|
||||||
|
return {"site": get_current_site(request)}
|
|
@ -65,7 +65,6 @@ MIDDLEWARE = [
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
"allauth.account.middleware.AccountMiddleware",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = "project.urls"
|
ROOT_URLCONF = "project.urls"
|
||||||
|
@ -81,9 +80,7 @@ TEMPLATES = [
|
||||||
"django.template.context_processors.request",
|
"django.template.context_processors.request",
|
||||||
"django.contrib.auth.context_processors.auth",
|
"django.contrib.auth.context_processors.auth",
|
||||||
"django.contrib.messages.context_processors.messages",
|
"django.contrib.messages.context_processors.messages",
|
||||||
],
|
"project.context_processors.current_site",
|
||||||
"builtins": [
|
|
||||||
"django.templatetags.i18n",
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,384 +0,0 @@
|
||||||
/* Reset */
|
|
||||||
*, *::before, *::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
img, picture, video, canvas, svg {
|
|
||||||
display: block;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
input, button, textarea, select {
|
|
||||||
font: inherit;
|
|
||||||
}
|
|
||||||
p, h1, h2, h3, h4, h5, h6 {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
|
||||||
#root, #__next {
|
|
||||||
isolation: isolate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Variables */
|
|
||||||
:root {
|
|
||||||
/* Colors */
|
|
||||||
--light : #fff;
|
|
||||||
--light-dust : #f6f6f6;
|
|
||||||
--dust : #f1f1f1;
|
|
||||||
--medium-dust : #dadada;
|
|
||||||
--dark-dust : #bfbfbf;
|
|
||||||
--fade : #878787;
|
|
||||||
--twilight : #4a4a4a;
|
|
||||||
--dark : #2a2a2a;
|
|
||||||
--custard : #f0dcac;
|
|
||||||
--water : #a8f3f4;
|
|
||||||
--splash : #4b3aba;
|
|
||||||
|
|
||||||
/* Sizes */
|
|
||||||
--space : 12px;
|
|
||||||
--double-space : calc(var(--space) * 2);
|
|
||||||
--half-space : calc(var(--space) / 2);
|
|
||||||
--quarter-space : calc(var(--space) / 4);
|
|
||||||
--outer-space : var(--double-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1380px) {
|
|
||||||
:root {
|
|
||||||
--outer-space : 15%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
html, body {
|
|
||||||
height : 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
font-weight : 600;
|
|
||||||
color : var(--twilight);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight : 500;
|
|
||||||
color : var(--splash);
|
|
||||||
text-decoration : none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin : 0;
|
|
||||||
padding : 0;
|
|
||||||
background : var(--custard);
|
|
||||||
font-family : Inter;
|
|
||||||
font-weight : 400;
|
|
||||||
line-height : 1.6;
|
|
||||||
color : var(--dark);
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
display : flex;
|
|
||||||
padding : var(--double-space) var(--outer-space);
|
|
||||||
background : var(--light);
|
|
||||||
justify-content : space-between;
|
|
||||||
align-items : center;
|
|
||||||
}
|
|
||||||
|
|
||||||
header > h1 {
|
|
||||||
font-size : 1.44em;
|
|
||||||
}
|
|
||||||
|
|
||||||
header > a.logout {
|
|
||||||
padding : 6px 12px;
|
|
||||||
border-radius : 6px;
|
|
||||||
background : var(--twilight);
|
|
||||||
text-decoration : none;
|
|
||||||
color : var(--dust);
|
|
||||||
}
|
|
||||||
|
|
||||||
header > a.logout:hover {
|
|
||||||
background : var(--splash);
|
|
||||||
color : var(--light);
|
|
||||||
}
|
|
||||||
|
|
||||||
aside {
|
|
||||||
padding : var(--double-space) var(--outer-space);
|
|
||||||
background : var(--light);
|
|
||||||
}
|
|
||||||
|
|
||||||
aside > div {
|
|
||||||
background : var(--dust);
|
|
||||||
padding : var(--double-space);
|
|
||||||
border-radius : var(--quarter-space);
|
|
||||||
overflow : hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
aside > div > h2 {
|
|
||||||
font-size : 1.22em;
|
|
||||||
margin : 0 0 6px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
aside > div > figure {
|
|
||||||
width : 100px;
|
|
||||||
height : 100px;
|
|
||||||
border : 1px solid var(--dark-dust);
|
|
||||||
float : left;
|
|
||||||
margin-right : var(--double-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
aside > div > dl {
|
|
||||||
overflow : hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
aside > div > dl > dt {
|
|
||||||
float : left;
|
|
||||||
clear : left;
|
|
||||||
margin : 0 var(--double-space) 0 0;
|
|
||||||
width : 180px;
|
|
||||||
font-weight : 600;
|
|
||||||
color : var(--twilight);
|
|
||||||
}
|
|
||||||
|
|
||||||
nav {
|
|
||||||
display : block;
|
|
||||||
border-bottom : 1px solid var(--dark-dust);
|
|
||||||
background : var(--light);
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ol {
|
|
||||||
margin: 0 calc(var(--outer-space));
|
|
||||||
padding : 0;
|
|
||||||
list-style-type : none;
|
|
||||||
overflow : hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ol li {
|
|
||||||
margin : 0;
|
|
||||||
padding : 0;
|
|
||||||
float : left;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav > ol > li > a {
|
|
||||||
display : block;
|
|
||||||
padding : var(--half-space) var(--half-space) var(--quarter-space);
|
|
||||||
margin : 0 var(--space);
|
|
||||||
border-bottom : var(--half-space) solid transparent;
|
|
||||||
text-decoration : none;
|
|
||||||
color : var(--dark);
|
|
||||||
cursor : pointer;
|
|
||||||
font-weight : 500;
|
|
||||||
letter-spacing : 0.04em;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav > ol > li:first-child > a {
|
|
||||||
margin-left : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ol li a:hover {
|
|
||||||
border-color : rgba(0,0,0,0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ol li a.current {
|
|
||||||
font-weight : bold;
|
|
||||||
border-color : var(--splash);
|
|
||||||
color : var(--splash);
|
|
||||||
}
|
|
||||||
|
|
||||||
article {
|
|
||||||
padding : var(--double-space) var(--outer-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
article > div {
|
|
||||||
background : var(--dust);
|
|
||||||
padding : var(--double-space);
|
|
||||||
margin-bottom : var(--double-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
div.content-view > h2 {
|
|
||||||
margin : 0 0 var(--double-space) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.services {
|
|
||||||
display : flex;
|
|
||||||
justify-content : space-between;
|
|
||||||
gap : var(--double-space);
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.services > div,
|
|
||||||
div.infobox {
|
|
||||||
background : var(--light);
|
|
||||||
padding : var(--double-space);
|
|
||||||
border-radius : 6px;
|
|
||||||
flex : 240px;
|
|
||||||
max-width : 420px;
|
|
||||||
display : flex;
|
|
||||||
flex-flow : column;
|
|
||||||
justify-content : space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.infobox button {
|
|
||||||
margin-top : var(--double-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
div.services > div > div.description {
|
|
||||||
margin-bottom : var(--double-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
div.services > div > div.description > p {
|
|
||||||
margin-top : var(--half-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
div.services > div > a,
|
|
||||||
a.button,
|
|
||||||
button {
|
|
||||||
display : block;
|
|
||||||
color : var(--light);
|
|
||||||
background : var(--splash);
|
|
||||||
padding : var(--space) var(--double-space);
|
|
||||||
border-radius : 3px;
|
|
||||||
opacity : 0.9;
|
|
||||||
cursor : pointer;
|
|
||||||
text-align : center;
|
|
||||||
border : 0;
|
|
||||||
font-weight : 600;
|
|
||||||
letter-spacing : 0.03em;
|
|
||||||
text-decoration : none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.services > div > a:hover,
|
|
||||||
a.button:hover,
|
|
||||||
button:hover {
|
|
||||||
opacity : 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
article table {
|
|
||||||
width : 100%;
|
|
||||||
border-spacing : 0;
|
|
||||||
margin : var(--space) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
article table thead th {
|
|
||||||
text-align : left;
|
|
||||||
}
|
|
||||||
|
|
||||||
article table tbody tr:nth-child(odd) {
|
|
||||||
background : var(--medium-dust);
|
|
||||||
}
|
|
||||||
|
|
||||||
article table thead th,
|
|
||||||
article table tbody td {
|
|
||||||
padding : var(--half-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
form > div {
|
|
||||||
margin : 0 0 var(--double-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
form > div >label {
|
|
||||||
display : block;
|
|
||||||
margin : 0 0 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form > div > input[type="text"],
|
|
||||||
form > div > input[type="password"] {
|
|
||||||
border : 2px solid var(--twilight);
|
|
||||||
border-radius : 6px;
|
|
||||||
padding : 8px;
|
|
||||||
background : var(--light-dust);
|
|
||||||
width : 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#login {
|
|
||||||
height : 100%;
|
|
||||||
display : flex;
|
|
||||||
align-items : center;
|
|
||||||
justify-content : center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox {
|
|
||||||
border-radius : var(--space);
|
|
||||||
border : 6px solid white;
|
|
||||||
width : 800px;
|
|
||||||
height : 500px;
|
|
||||||
|
|
||||||
display : flex;
|
|
||||||
flex-flow : row;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox > div {
|
|
||||||
padding : var(--double-space);
|
|
||||||
flex : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox label {
|
|
||||||
color : var(--twilight);
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox > div.login {
|
|
||||||
background : var(--light-dust);
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox > div.signup {
|
|
||||||
background : var(--water);
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox > div:first-child {
|
|
||||||
border-radius : var(--half-space) 0 0 var(--half-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox > div:last-child {
|
|
||||||
border-radius : 0 var(--half-space) var(--half-space) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox > div:last-child > * {
|
|
||||||
flex : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox div.new_here {
|
|
||||||
margin-top : var(--double-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox div.new_here h2 {
|
|
||||||
margin: var(--double-space) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox button {
|
|
||||||
width : 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loginbox img {
|
|
||||||
padding : 0 var(--double-space);
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
margin : var(--space) var(--outer-space);
|
|
||||||
padding : var(--space);
|
|
||||||
border-radius : var(--quarter-space);
|
|
||||||
background : var(--dark);
|
|
||||||
color : var(--dust);
|
|
||||||
font-size : 0.78em;
|
|
||||||
opacity : 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.time_remaining {
|
|
||||||
color : var(--fade);
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination {
|
|
||||||
display : flex;
|
|
||||||
justify-content : center;
|
|
||||||
list-style : none;
|
|
||||||
padding : 0;
|
|
||||||
margin : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination > li {
|
|
||||||
margin : 0 6px;
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,200 +0,0 @@
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Thin.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-Thin.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 100;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-ThinItalic.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-ThinItalic.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 200;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-ExtraLight.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-ExtraLight.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 200;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-ExtraLightItalic.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-ExtraLightItalic.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Light.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-Light.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 300;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-LightItalic.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-LightItalic.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Regular.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-Regular.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Italic.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-Italic.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Medium.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-Medium.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 500;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-MediumItalic.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-MediumItalic.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-SemiBold.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-SemiBold.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-SemiBoldItalic.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-SemiBoldItalic.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Bold.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-Bold.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-BoldItalic.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-BoldItalic.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 800;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-ExtraBold.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-ExtraBold.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 800;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-ExtraBoldItalic.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-ExtraBoldItalic.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Black.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-Black.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-BlackItalic.woff2?v=3.19") format("woff2"),
|
|
||||||
url("Inter-BlackItalic.woff?v=3.19") format("woff");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------
|
|
||||||
Variable font.
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
html { font-family: 'Inter', sans-serif; }
|
|
||||||
@supports (font-variation-settings: normal) {
|
|
||||||
html { font-family: 'Inter var', sans-serif; }
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter var';
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
font-style: normal;
|
|
||||||
font-named-instance: 'Regular';
|
|
||||||
src: url("Inter-roman.var.woff2?v=3.19") format("woff2");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter var';
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
font-style: italic;
|
|
||||||
font-named-instance: 'Italic';
|
|
||||||
src: url("Inter-italic.var.woff2?v=3.19") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------
|
|
||||||
[EXPERIMENTAL] Multi-axis, single variable font.
|
|
||||||
|
|
||||||
Slant axis is not yet widely supported (as of February 2019) and thus this
|
|
||||||
multi-axis single variable font is opt-in rather than the default.
|
|
||||||
|
|
||||||
When using this, you will probably need to set font-variation-settings
|
|
||||||
explicitly, e.g.
|
|
||||||
|
|
||||||
* { font-variation-settings: "slnt" 0deg }
|
|
||||||
.italic { font-variation-settings: "slnt" 10deg }
|
|
||||||
|
|
||||||
*/
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter var experimental';
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
font-style: oblique 0deg 10deg;
|
|
||||||
src: url("Inter.var.woff2?v=3.19") format("woff2");
|
|
||||||
}
|
|
|
@ -4,8 +4,6 @@
|
||||||
|
|
||||||
{% block non_login_content %}
|
{% block non_login_content %}
|
||||||
|
|
||||||
<div id="loginbox">
|
|
||||||
<div class="login">
|
|
||||||
{% if form.non_field_errors %}
|
{% if form.non_field_errors %}
|
||||||
{% for error in form.non_field_errors %}
|
{% for error in form.non_field_errors %}
|
||||||
<div class="alert alert-danger" role="alert">
|
<div class="alert alert-danger" role="alert">
|
||||||
|
@ -13,11 +11,10 @@
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<h2>Log in</h2>
|
|
||||||
|
|
||||||
<form method="post" action="">
|
<form method="post" action="">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div>
|
|
||||||
<label for="id_username"
|
<label for="id_username"
|
||||||
class="visually-hidden">
|
class="visually-hidden">
|
||||||
{% trans "E-mail" %}
|
{% trans "E-mail" %}
|
||||||
|
@ -29,8 +26,7 @@
|
||||||
placeholder="{% trans "E-mail" %}"
|
placeholder="{% trans "E-mail" %}"
|
||||||
required
|
required
|
||||||
autofocus>
|
autofocus>
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="id_password" class="visually-hidden">
|
<label for="id_password" class="visually-hidden">
|
||||||
{% trans "Password" %}
|
{% trans "Password" %}
|
||||||
</label>
|
</label>
|
||||||
|
@ -40,25 +36,21 @@
|
||||||
class="form-control mb-lg-2"
|
class="form-control mb-lg-2"
|
||||||
placeholder="{% trans "Password" %}"
|
placeholder="{% trans "Password" %}"
|
||||||
required>
|
required>
|
||||||
</div>
|
|
||||||
<div>
|
<button class="w-100 mb-lg-2 btn btn-lg btn-primary"
|
||||||
<button type="submit">{% trans "Sign in" %}</button>
|
type="submit">{% trans "Sign in" %}</button>
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
<div>
|
|
||||||
<a href="{% url "account_reset_password" %}"
|
<a href="{% url "account_reset_password" %}"
|
||||||
class="w-100 btn btn-lg btn-outline-info">
|
class="w-100 btn btn-lg btn-outline-info">
|
||||||
{% trans "Forgot password?" %}
|
{% trans "Forgot password?" %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
</div>
|
<hr class="hr-text" data-content="{% trans "Or"|upper %}">
|
||||||
<div class="signup">
|
|
||||||
<img src="https://data.coop/static/img/logo_da.svg" alt="data.coop logo">
|
<a class="w-100 btn btn-lg btn-outline-success"
|
||||||
<div class="new_here">
|
type="submit"
|
||||||
<h2> Are you new here? </h2>
|
href="{% url "account_signup" %}">
|
||||||
<a class="button" href="{% url "account_signup" %}">{% trans "Become a member" %}</a>
|
{% trans "Become a member" %}
|
||||||
</div>
|
</a>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -5,18 +5,17 @@
|
||||||
{% block head_title %}{% trans "Sign Out" %}{% endblock %}
|
{% block head_title %}{% trans "Sign Out" %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="content-view">
|
<h1>{% trans "Sign Out" %}</h1>
|
||||||
<h2>{% trans "Sign Out" %}</h2>
|
|
||||||
|
|
||||||
<p>{% trans 'Are you sure you want to sign out?' %}</p>
|
<p>{% trans 'Are you sure you want to sign out?' %}</p>
|
||||||
|
|
||||||
<form method="post" action="{% url 'account_logout' %}">
|
<form method="post" action="{% url 'account_logout' %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% if redirect_field_value %}
|
{% if redirect_field_value %}
|
||||||
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
|
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<button type="submit">{% trans 'Sign Out' %}</button>
|
<button type="submit">{% trans 'Sign Out' %}</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -7,13 +7,71 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<title>Login – {{ site.name }}</title>
|
<title>Login – {{ site.name }}</title>
|
||||||
<link rel="stylesheet" href="{% static "/fonts/inter.css" %}">
|
|
||||||
<link rel="stylesheet" href="{% static "/css/style.css" %}">
|
<link href="{% static "/css/bootstrap.min.css" %}" rel="stylesheet"
|
||||||
|
crossorigin="anonymous">
|
||||||
|
|
||||||
|
<link href="{% static "/css/bootstrap-icons.css" %}" rel="stylesheet"
|
||||||
|
crossorigin="anonymous">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 40px;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
background-color: #a8f3f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 330px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin .checkbox {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin .form-control {
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: auto;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin .form-control:focus {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hr-text:after {
|
||||||
|
content: attr(data-content);
|
||||||
|
padding: 0 4px;
|
||||||
|
position: relative;
|
||||||
|
top: -13px;
|
||||||
|
background-color: #a8f3f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="text-center">
|
||||||
<main id="login">
|
|
||||||
|
<main class="form-signin">
|
||||||
|
<img class="mb-4" src="https://new.data.coop/static/img/logo_da.svg" alt=""
|
||||||
|
width="260" height="160">
|
||||||
|
|
||||||
{% block non_login_content %}
|
{% block non_login_content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -3,82 +3,211 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<title>{% block head_title %}{% endblock %} – {{ site.name }}</title>
|
<title>{% block head_title %}{% endblock %} – {{ site.name }}</title>
|
||||||
<link rel="stylesheet" href="{% static "fonts/inter.css" %}">
|
|
||||||
<link rel="stylesheet" href="{% static "css/style.css" %}">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<h1> data.coop membersystem </h1>
|
|
||||||
<a class="logout" href="{% url "account_logout" %}">Log out</a>
|
|
||||||
</header>
|
|
||||||
<main>
|
|
||||||
<aside>
|
|
||||||
<div>
|
|
||||||
<figure></figure>
|
|
||||||
<h2>{{ user }}</h2>
|
|
||||||
|
|
||||||
{% if current_membership %}
|
<link href="{% static "/css/bootstrap.min.css" %}" rel="stylesheet"
|
||||||
<dl>
|
crossorigin="anonymous">
|
||||||
<dt>Membership</dt>
|
|
||||||
<dd>
|
|
||||||
Active
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Period</dt>
|
<link href="{% static "/css/bootstrap-icons.css" %}" rel="stylesheet"
|
||||||
<dd>
|
crossorigin="anonymous">
|
||||||
Until {{ current_period.upper }} <span class="time_remaining">({{ current_period.upper|timeuntil }})</span>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Membership type</dt>
|
<style>
|
||||||
<dd>Normal member</dd>
|
body {
|
||||||
</dl>
|
font-size: .875rem;
|
||||||
{% else %}
|
}
|
||||||
Your membership status will be displayed here in the future.
|
|
||||||
{% endif %}
|
/*
|
||||||
</div>
|
* Sidebar
|
||||||
</aside>
|
*/
|
||||||
<nav>
|
|
||||||
<ol>
|
.sidebar {
|
||||||
<li>
|
position: fixed;
|
||||||
<a href="/" class="{% active_path "index" "current" %}">
|
top: 0;
|
||||||
Dashboard
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 100; /* Behind the navbar */
|
||||||
|
padding: 48px 0 0; /* Height of navbar */
|
||||||
|
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
.sidebar {
|
||||||
|
top: 5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-sticky {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
height: calc(100vh - 48px);
|
||||||
|
padding-top: .5rem;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link .feather {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: #727272;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link.active {
|
||||||
|
color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link:hover .feather,
|
||||||
|
.sidebar .nav-link.active .feather {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-heading {
|
||||||
|
font-size: .75rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Navbar
|
||||||
|
*/
|
||||||
|
|
||||||
|
.navbar-brand {
|
||||||
|
padding-top: .75rem;
|
||||||
|
padding-bottom: .75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
background-color: rgba(0, 0, 0, .25);
|
||||||
|
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar .navbar-toggler {
|
||||||
|
top: .25rem;
|
||||||
|
right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar .form-control {
|
||||||
|
padding: .75rem 1rem;
|
||||||
|
border-width: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-dark {
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(255, 255, 255, .1);
|
||||||
|
border-color: rgba(255, 255, 255, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-dark:focus {
|
||||||
|
border-color: transparent;
|
||||||
|
box-shadow: 0 0 0 3px rgba(255, 255, 255, .25);
|
||||||
|
} </style>
|
||||||
|
|
||||||
|
<script src="{% static "js/bootstrap.bundle.min.js" %}"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
|
||||||
|
<a class="navbar-brand col-md-3 col-lg-2 me-0 px-3" href="#">{{ site.name }}</a>
|
||||||
|
<button class="navbar-toggler position-absolute d-md-none collapsed" type="button"
|
||||||
|
data-bs-toggle="collapse" data-bs-target="#sidebarMenu"
|
||||||
|
aria-controls="sidebarMenu" aria-expanded="false"
|
||||||
|
aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="navbar-nav px-3">
|
||||||
|
<li class="nav-item text-nowrap">
|
||||||
|
<a class="nav-link" href="{% url "account_logout" %}">
|
||||||
|
<i class="bi bi-person-circle"></i>
|
||||||
|
Sign out</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<nav id="sidebarMenu"
|
||||||
|
class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
|
||||||
|
<div class="position-sticky pt-3">
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% active_path "index" "active" %}"
|
||||||
|
href="{% url "index" %}">
|
||||||
|
{% trans "Dashboard" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
{% comment %}
|
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||||
<li>
|
<span>{% trans "Profile" %}</span>
|
||||||
<a href="/services" class="{% active_path "services" "current" %}">
|
</h6>
|
||||||
Services
|
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">
|
||||||
|
{% trans "Details" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endcomment %}
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% active_path "account_email" "active" %}"
|
||||||
<li>
|
aria-current="page" href="{% url "account_email" %}">
|
||||||
<a href="{% url "account_email" %}" class="{% active_path "account_email" "current" %}">
|
{% trans "Emails" %}
|
||||||
Email
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||||
|
<span>{% trans "Membership" %}</span>
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% active_path "membership-overview" "active" %}"
|
||||||
|
aria-current="page" href="{% url "membership-overview" %}">
|
||||||
|
{% trans "Overview" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||||
|
<span>{% trans "Services" %}</span>
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% active_path "services-overview" "active" %}"
|
||||||
|
href="{% url "services-overview" %}">
|
||||||
|
{% trans "Overview" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
{% if perms.membership.administrate_memberships %}
|
{% if perms.membership.administrate_memberships %}
|
||||||
<li>
|
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||||
<a href="{% url "admin-members" %}" class="{% active_path "admin-members" "current" %}">
|
<span>{% trans "Admin" %}</span>
|
||||||
Admin
|
</h6>
|
||||||
|
<ul class="nav flex-column mb-2">
|
||||||
|
<li class="nav-item {% active_path "admin-members" "active" %}">
|
||||||
|
<a class="nav-link" href="{% url "admin-members" %}">
|
||||||
|
<span data-feather="file-text"></span>
|
||||||
|
{% trans "Members" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ol>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<article>
|
|
||||||
{% block content %}{% endblock %}
|
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4 p-4">
|
||||||
</article>
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
</div>
|
||||||
data.coop membersystem version 0.0.1
|
</div>
|
||||||
</footer>
|
</body>
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,28 +1 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block head_title %}
|
|
||||||
{% trans "Home" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="content-view">
|
|
||||||
<h2>Welcome {{ user }}!</h2>
|
|
||||||
<p>
|
|
||||||
This is the new member area.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
It is very much under construction.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{% comment %}
|
|
||||||
<hr>
|
|
||||||
<br>
|
|
||||||
<div class="infobox">
|
|
||||||
<p>
|
|
||||||
To get started we need you to verify your email!
|
|
||||||
</p>
|
|
||||||
<button>Verify email</button>
|
|
||||||
</div>
|
|
||||||
{% endcomment %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
@ -1,62 +1,10 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<p>
|
||||||
<div class="content-view">
|
Services and signup to these will be
|
||||||
Coming soon!
|
</p>
|
||||||
</div>
|
<p>
|
||||||
|
This is yet to be implemented.
|
||||||
{% comment %}
|
</p>
|
||||||
<div class="content-view">
|
|
||||||
<h2>Services you subscribe to</h2>
|
|
||||||
<div class="services">
|
|
||||||
<div>
|
|
||||||
<div class="description">
|
|
||||||
<h3>Passit</h3>
|
|
||||||
<p>Passit is a service that blabla</p>
|
|
||||||
<a href="#">Read more …</a>
|
|
||||||
</div>
|
|
||||||
<a>Unsubscribe</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content-view">
|
|
||||||
<h2>Available services</h2>
|
|
||||||
<div class="services">
|
|
||||||
<div>
|
|
||||||
<div class="description">
|
|
||||||
<h3>Forgejo</h3>
|
|
||||||
<p>Forgejo is a service that blabla</p>
|
|
||||||
<a href="#">Read more …</a>
|
|
||||||
</div>
|
|
||||||
<a>Subscribe</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="description">
|
|
||||||
<h3>Mastodon</h3>
|
|
||||||
<p>Mastodon is a service where you can write things to people around the world.</p>
|
|
||||||
<a href="#">Read more …</a>
|
|
||||||
</div>
|
|
||||||
<a>Subscribe</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="description">
|
|
||||||
<h3>Matrix</h3>
|
|
||||||
<p>Matrix is a service that blabla</p>
|
|
||||||
<a href="#">Read more …</a>
|
|
||||||
</div>
|
|
||||||
<a>Subscribe</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="description">
|
|
||||||
<h3>NextCloud</h3>
|
|
||||||
<p>NextCloud is a service that blabla</p>
|
|
||||||
<a href="#">Read more …</a>
|
|
||||||
</div>
|
|
||||||
<a>Subscribe</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endcomment %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -13,7 +13,7 @@ from membership.views import membership_overview
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", login_required(index), name="index"),
|
path("", login_required(index), name="index"),
|
||||||
path("services/", login_required(services_overview), name="services"),
|
path("services/", login_required(services_overview), name="services-overview"),
|
||||||
path("membership/", membership_overview, name="membership-overview"),
|
path("membership/", membership_overview, name="membership-overview"),
|
||||||
path("admin/members/", members_admin, name="admin-members"),
|
path("admin/members/", members_admin, name="admin-members"),
|
||||||
path(
|
path(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from utils.view_utils import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
|
|
|
@ -3,6 +3,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class CreatedModifiedAbstract(models.Model):
|
class CreatedModifiedAbstract(models.Model):
|
||||||
|
|
||||||
modified = models.DateTimeField(auto_now=True, verbose_name=_("modified"))
|
modified = models.DateTimeField(auto_now=True, verbose_name=_("modified"))
|
||||||
created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
|
created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block head_title %}
|
|
||||||
{{ entity_name_plural|capfirst }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="content-view">
|
|
||||||
|
|
||||||
<h1>
|
<h1>
|
||||||
{{ entity_name_plural|capfirst }} <small class="text-muted">{{ total_count }}</small>
|
Users <small class="text-muted">{{ total_count }}</small>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
|
@ -50,6 +44,7 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
|
<nav aria-label="Page navigation example">
|
||||||
<ul class="pagination justify-content-center">
|
<ul class="pagination justify-content-center">
|
||||||
|
|
||||||
{% if not page.has_previous %}
|
{% if not page.has_previous %}
|
||||||
|
@ -102,9 +97,8 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -5,17 +5,9 @@ register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag(takes_context=True)
|
@register.simple_tag(takes_context=True)
|
||||||
def active_path(context, path_name, class_name) -> str | None:
|
def active_path(context, path_name, class_name):
|
||||||
"""Return the given class name if the current path matches the given path name."""
|
|
||||||
|
|
||||||
path = reverse(path_name)
|
path = reverse(path_name)
|
||||||
request_path = context.get("request").path
|
request_path = context.get("request").path
|
||||||
|
|
||||||
# Check if the current path matches the given path name.
|
if path == request_path or ("basepath" in context and context["basepath"] == path):
|
||||||
is_path = path == request_path
|
|
||||||
|
|
||||||
# Check if the current path is a sub-path of the given path name.
|
|
||||||
is_base_path = "base_path" in context and reverse(context["base_path"]) == path
|
|
||||||
|
|
||||||
if is_path or is_base_path:
|
|
||||||
return class_name
|
return class_name
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
import contextlib
|
import contextlib
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
|
||||||
from django.core.exceptions import FieldError
|
from django.core.exceptions import FieldError
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from zen_queries import queries_disabled
|
from zen_queries import render
|
||||||
from zen_queries import render as zen_queries_render
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -46,8 +43,6 @@ class RowAction:
|
||||||
|
|
||||||
def render_list(
|
def render_list(
|
||||||
request: HttpRequest,
|
request: HttpRequest,
|
||||||
entity_name: str,
|
|
||||||
entity_name_plural: str,
|
|
||||||
objects: list["Model"],
|
objects: list["Model"],
|
||||||
columns: list[tuple[str, str]],
|
columns: list[tuple[str, str]],
|
||||||
row_actions: list[RowAction] = None,
|
row_actions: list[RowAction] = None,
|
||||||
|
@ -75,7 +70,6 @@ def render_list(
|
||||||
|
|
||||||
rows = []
|
rows = []
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
with queries_disabled():
|
|
||||||
row = Row(
|
row = Row(
|
||||||
data={column: getattr(obj, column[0]) for column in columns},
|
data={column: getattr(obj, column[0]) for column in columns},
|
||||||
actions=[action.render(obj) for action in row_actions],
|
actions=[action.render(obj) for action in row_actions],
|
||||||
|
@ -89,8 +83,6 @@ def render_list(
|
||||||
"list_actions": list_actions,
|
"list_actions": list_actions,
|
||||||
"total_count": total_count,
|
"total_count": total_count,
|
||||||
"order_by": order_by,
|
"order_by": order_by,
|
||||||
"entity_name": entity_name,
|
|
||||||
"entity_name_plural": entity_name_plural,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if paginate_by:
|
if paginate_by:
|
||||||
|
@ -104,20 +96,3 @@ def render_list(
|
||||||
template_name="utils/list.html",
|
template_name="utils/list.html",
|
||||||
context=context,
|
context=context,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def base_context(request: HttpRequest) -> dict[str, Any]:
|
|
||||||
"""
|
|
||||||
Return a base context for all views.
|
|
||||||
"""
|
|
||||||
return {"site": get_current_site(request)}
|
|
||||||
|
|
||||||
|
|
||||||
def render(request, template_name, context=None):
|
|
||||||
"""
|
|
||||||
Render a template with a base context.
|
|
||||||
"""
|
|
||||||
if context is None:
|
|
||||||
context = {}
|
|
||||||
context = base_context(request) | context
|
|
||||||
return zen_queries_render(request, template_name, context)
|
|
||||||
|
|
Loading…
Reference in a new issue