Compare commits

...

397 commits
0.4.0 ... main

Author SHA1 Message Date
Jan Dittberner 11c04df074 Add flatpage URL for /issues/
Jira has been decommissioned and replaced with a flatpage
2024-02-11 13:12:54 +01:00
Jan Dittberner 7c57b4cc94 Update docker setup 2024-02-11 13:12:26 +01:00
Jan Dittberner 78e06dd2b9 Update dependencies
- updated minimum version of several dependencies in pyproject.toml
- update of django-allauth required to add
  allauth.account.middleware.AccountMiddleware to MIDDLEWARE setting
2024-01-13 13:38:03 +01:00
Jan Dittberner 90795375e7 Update dependencies 2024-01-13 13:22:50 +01:00
Jan Dittberner c1b226e5a1 Update dependency versions 2023-08-03 09:24:42 +02:00
Jan Dittberner 5e527ef10d Release 0.15.1 2023-07-23 11:24:46 +02:00
Jan Dittberner 3b6d50a62a Remove stale disk usage stats 2023-07-23 11:24:10 +02:00
Jan Dittberner 4b74f5d04b Release 0.15.0 2023-07-23 10:28:00 +02:00
Jan Dittberner ec6a9a7cc1 Add disk usage details for mail and web
Addresses #10
2023-07-23 10:26:43 +02:00
Jan Dittberner f21987158b Release 0.14.4 2023-07-22 22:35:49 +02:00
Jan Dittberner 2e7dca529a Add customer to disk space detail view 2023-07-22 22:34:44 +02:00
Jan Dittberner 1d4f070867 Release 0.14.3 2023-07-22 22:25:36 +02:00
Jan Dittberner d1494af0a1 Fix permission check on disk space detail view 2023-07-22 22:25:08 +02:00
Jan Dittberner 69638b6b6d Release 0.14.2 2023-07-22 21:57:40 +02:00
Jan Dittberner ee561a5127 Fix division by zero 2023-07-22 21:56:53 +02:00
Jan Dittberner b69ecbfa2d Prepare release 0.14.1 2023-07-22 20:46:47 +02:00
Jan Dittberner bf7b02d5b5 Fix squashed migration 2023-07-22 20:46:03 +02:00
Jan Dittberner 22945f72bf Prepare release
- update changelog
- update dependencies
- bump version
2023-07-22 20:12:00 +02:00
Jan Dittberner d0fe915612 Update german translation 2023-07-22 20:07:01 +02:00
Jan Dittberner cb62bd63e2 Add disk usage statistics
- add model CustomerPackageDiskUsage for hosting package disk usage
  statistics
- add REST API endpoint for submittings statistics for disk, mysql and
  pgsql usage
- add disk usage information to hosting package detail view
- add separate hosting package disk usage statistic view
2023-07-22 19:43:10 +02:00
Jan Dittberner affb49a971 Update to Django 4.2
- fix deprecation warnings
- update dependencies
2023-07-08 19:21:02 +02:00
Jan Dittberner 8aadae1c83 Fix Django4 deprecation warnings 2023-07-08 18:34:12 +02:00
Jan Dittberner 30ffdf1751 Update dependencies 2023-07-08 17:01:49 +02:00
Jan Dittberner aed8e97dbc Fix Poetry deprecation warning 2023-07-08 16:59:04 +02:00
Jan Dittberner 4577ec4896 Release 0.13.0
- update changelog
2023-05-08 17:26:05 +02:00
Jan Dittberner 8c7af9a246 Add queue information to user delete task chain 2023-05-07 14:47:30 +02:00
Jan Dittberner 175ffd19f4 Add queue to file server tasks 2023-05-07 14:41:56 +02:00
Jan Dittberner 27e9d27b2b Fix TaskResult.fetch_results 2023-05-07 14:02:10 +02:00
Jan Dittberner 3b04595c7a Add better handling for missing groups 2023-05-07 13:45:30 +02:00
Jan Dittberner c7fda0e993 Add log file configuration support 2023-05-06 14:09:25 +02:00
Jan Dittberner 376cfab88f Fix output of response_for_exception in tests
Django has a django.core.handlers.exception.response_for_exception that
handles SuspiciousOperationException, that is expected behaviour and
should not be logged in test output.
2023-05-02 17:57:13 +02:00
Jan Dittberner be328758e6 Update dependencies 2023-05-02 17:44:39 +02:00
Jan Dittberner d88745f46b Fix tests 2023-04-29 13:10:25 +02:00
Jan Dittberner 866f6c8083 Remove duplicate functionality
- remove customer hosting package list
- replace useless dashboard with redirect
- move all hosting package list for superuser to top level menu item
- replace btn-default with btn-secondary
- improve email address management page
2023-04-29 12:35:49 +02:00
Jan Dittberner 2d05580ed3 Improve taskresults app
- show created/modified fields in admin
- add verbose output to management command
- add date hierarchy and action filters in admin
2023-04-29 11:13:38 +02:00
Jan Dittberner 397e479925 Update dependencies 2023-04-29 10:33:31 +02:00
Jan Dittberner 5db97f03d1 Use correct settings for celery 2023-04-29 10:33:17 +02:00
Jan Dittberner 0962891a9b Implement invoice model and admin API 2023-04-23 14:43:44 +02:00
Jan Dittberner a136bcc52b List OS user in admin hosting package list 2023-04-22 13:16:13 +02:00
Jan Dittberner 806ee80a85 Move contact_form templates to contact_form app 2023-04-22 13:14:24 +02:00
Jan Dittberner 10628ee45f Add translation for user name part 2023-04-22 12:58:26 +02:00
Jan Dittberner be1ed6ecea Add styling for impersonate views 2023-04-22 12:56:05 +02:00
Jan Dittberner 9fbd608837 Use signals for website celery tasks 2023-04-17 19:42:49 +02:00
Jan Dittberner 8e42cb9c18 Start switch to Bootstrap 5
- drop jQuery and fontawesome dependencies
- add bootstrap5 and bootstrap-icons
- update fonts mfizz
- update base templates and the first set of other templates
- replace blocktrans and trans with blocktranslate and translate to
  prepare for Django 4
- move hostingpakcage templates to hostingpackages/templates
- update translations
2023-04-16 22:11:32 +02:00
Jan Dittberner 5cf7ef7a23 Strip API to required minimum
- disable browseable API
- use IsAdminUser for DEFAULT_PERMISSION_CLASSES
- register explicit API views for HelpUser model
2023-04-16 14:34:45 +02:00
Jan Dittberner 0f91587c60 Remove unneeded users API view
The help-users API view is sufficient
2023-04-16 13:50:01 +02:00
Jan Dittberner a65b1574db Add admin user information REST API 2023-04-16 13:21:57 +02:00
Jan Dittberner 9731d4e793 Add Django REST framework dependencies 2023-04-16 12:24:32 +02:00
Jan Dittberner f9ea88cd24 Add new app 'help' for user support
This commit adds a new model that enhances the user profile with an
offline support code, a postal address and an email address to allow
users to reset their profile.

The commit adds to Django admin commands 'populate' and
'reset_offline_code' to maintain the help user profiles from the Django
command line.
2023-04-16 12:20:37 +02:00
Jan Dittberner 4b7e311c62 Remove tests for removed models 2023-04-16 11:14:26 +02:00
Jan Dittberner 37f3ed2506 Update changelog 2023-04-15 12:12:02 +02:00
Jan Dittberner e44bdd7be2 Bump version to 0.13.0 2023-04-15 12:07:12 +02:00
Jan Dittberner 345b32f286 Remove unused powerdns support tables 2023-04-15 12:06:44 +02:00
Jan Dittberner d499b781d4 Implement impersonation 2023-04-15 11:48:53 +02:00
Jan Dittberner 472e272305 Remove Twitter login, disable signups 2023-04-14 19:56:41 +02:00
Jan Dittberner dd67ee91da Require login for index view 2023-04-14 19:33:44 +02:00
Jan Dittberner a5b65974fb Remove django-braces requirement 2023-04-14 19:16:58 +02:00
Jan Dittberner 35aae85c8d Move dashboard templates to dashboard app 2023-04-14 19:16:30 +02:00
Jan Dittberner 3452e2a8c2 Update dependencies 2023-04-14 18:43:11 +02:00
Jan Dittberner f89de16f6e Improve docker build
- add .dockerignore
- add entrypoint.sh to ensure proper permissions in Docker volumes
- add TZ variable for consistent Celery timestamps
2023-02-20 15:39:14 +01:00
Jan Dittberner 38dae51a7a Unify with gvaldap/gvaweb 2023-02-19 17:48:25 +01:00
Jan Dittberner d2f94c7bec Fix Dockerfile for poetry 2023-02-19 15:53:00 +01:00
Jan Dittberner fc8f22432c Fix skipped tests in managemails 2023-02-19 15:13:31 +01:00
Jan Dittberner a8392ef91e Use sha512_crypt from passlib.handlers.sha2_crypt 2023-02-19 13:47:08 +01:00
Jan Dittberner 610f8976fc Refactor managemails to use signals
- use signals to trigger Celery tasks to create and delete mailboxes
- add generic TestCaseWithCeleryTasks class to handle celery task tests
  in a uniform way
2023-02-19 13:45:30 +01:00
Jan Dittberner d6fc29a2b8 Update to gvacommon 0.6.0 2023-02-19 12:38:19 +01:00
Jan Dittberner 4af1a39ca4 Upgrade to Django 3.2
- update dependencies
- fix deprecation warnings
- fix tests
- skip some tests that need more work
- reformat changed code with isort and black
2023-02-18 22:46:48 +01:00
Jan Dittberner 0f18e59d67 Fix deprecation warnings 2023-02-18 19:07:33 +01:00
Jan Dittberner b3588b5e6c Ignore direnv .envrc 2023-02-18 19:07:21 +01:00
Jan Dittberner 03250cef00 Switch from pipenv to poetry 2023-02-18 19:07:05 +01:00
Jan Dittberner 0c17f03489 Release 0.12.1
- fix internal server error when displaying a customer hosting package
   with an undefined mail domain
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEKHuXKkUYdvdO9493DXkdyNc3wdkFAl6UY00ACgkQDXkdyNc3
 wdmM7Qf9HRWH41CNjC8PVxehVPTWFRNsoV9GZYIe5PWcywaOuVLWScUoPbr8FFUk
 dIZsgZl7Qc5yGcAGysD7L/OqDT40OByrShVsZ3onZZta8N2kbOIErbqdtqzOEOWy
 OYMMtjalqdEDsCnrVA35izyaAFvIlgsVZ/HthYMsye78aZolOMb18zTbzGxpMnNz
 il6EQUubMuSinMA7O71Jp9VrEm2BEmVrMW3/Bo7CI+byLMviy2nwfN4/DuTV/x6m
 8Zkx/p5EKBzbqqgtx2gi1bcZdj9XMe7ctMCoaLdSGCf1Q22EgVXKdBB5lWWwmuoQ
 h9utxqnY+JdlOmN64/npE3JYXF0s7A==
 =wx92
 -----END PGP SIGNATURE-----

Merge tag '0.12.1'

Release 0.12.1

- fix internal server error when displaying a customer hosting package
  with an undefined mail domain

* tag '0.12.1':
  Add release version to changelog
  Bump version number
  Do not show add_mailaddress for nonexistant mail domain
2020-04-13 15:04:18 +02:00
Jan Dittberner df3628499d Merge branch 'hotfix/0.12.1' into production
* hotfix/0.12.1:
  Add release version to changelog
  Bump version number
  Do not show add_mailaddress for nonexistant mail domain
2020-04-13 15:03:43 +02:00
Jan Dittberner f220b865ff Add release version to changelog 2020-04-13 15:02:53 +02:00
Jan Dittberner a1084ec785 Bump version number 2020-04-13 15:01:37 +02:00
Jan Dittberner 2328abe8db Do not show add_mailaddress for nonexistant mail domain
Fixes #7
2020-04-13 14:59:56 +02:00
Jan Dittberner b12a891fd7 Release 0.12.0
- Update to Python 3 and Django 2.2
 - improve development setup and documentation
 - integrate previous bugfix releases
 -----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCgAyFiEEKHuXKkUYdvdO9493DXkdyNc3wdkFAl6QaMwUHGphbkBkaXR0
 YmVybmVyLmluZm8ACgkQDXkdyNc3wdnCUAf9H5wDLxRuPuow0rkli5XSNl/RWBMh
 tz10A7mO8QWJNcbGVSAw9Jol99htLTJb0MoyyonQKONfxlD4ro/0aDFsVJFRaH7M
 D9EQlmQuhm/3hvcDbO9+maEaZvPWYFYHuQQJpwDmAjuMnsXN7SxPEqq4Wu8OVB6G
 ebxuqR58MxJwmDEkZyA1D339gCbIo3PWWNeVInC8Gv9/yvhNx5KX0LrR8kRCpsWv
 N6YJ6DtMYo7UtqmdJmVa1xTlX6rG7znAIlC4gSXoRBspxeH3upd66KV1YkWqM+qd
 Iuum+4uRZfjkU2DRLNprxvHYp78sRQXBps4Kelo9LU/wbwUlHjnr6qS0Pg==
 =uD2Q
 -----END PGP SIGNATURE-----

Merge tag '0.12.0'

Release 0.12.0

- Update to Python 3 and Django 2.2
- improve development setup and documentation
- integrate previous bugfix releases
2020-04-10 14:38:40 +02:00
Jan Dittberner 000391a808 Merge branch 'release/0.12.0' into production 2020-04-10 14:37:56 +02:00
Jan Dittberner 9e3b7ba133 Update install documentation 2020-04-10 14:36:22 +02:00
Jan Dittberner 73b70bf35f Fix documentation build 2020-04-10 14:34:41 +02:00
Jan Dittberner 42b6f8d91d Bump version to 0.12.0 2020-04-10 14:19:36 +02:00
Jan Dittberner 6a88ef6bd3 Update changelog 2020-04-10 14:18:29 +02:00
Jan Dittberner b1da42e6b7 Update dependencies 2020-04-10 14:04:13 +02:00
Jan Dittberner 5b70494863 Document current project page 2020-04-05 14:32:17 +02:00
Jan Dittberner d90c0e096c Add PNG export of architecture diagram 2020-04-05 14:24:43 +02:00
Jan Dittberner 367a3197a1 Add architecture diagram 2020-04-05 14:22:35 +02:00
Jan Dittberner 5bd55bc418 Update dependencies 2020-04-04 14:08:02 +02:00
Jan Dittberner 47a1e1dc55 Fix settings to work with salt state definitions
- move from assets to static
2020-03-07 18:25:49 +01:00
Jan Dittberner fda129e81a Add mysql node to docker-compose setup 2020-03-04 20:43:04 +01:00
Jan Dittberner d10eaee382 Add file node to docker-compose setup 2020-03-04 17:19:40 +01:00
Jan Dittberner 0bf37d1bea Improve docker setup
Add gvaweb and gvaldap containers to docker-compose.yml. Unify most of
Dockerfile with gvaweb and gvaldap. Add empty directories for mounting
asset and media files into bind mounted docker volumes. Run application
as separate system user.
2020-03-03 13:11:46 +01:00
Jan Dittberner 54c1fbfed0 Update dependencies 2020-03-03 13:11:46 +01:00
Jan Dittberner 8675359586 Merge tag '0.11.6'
Release 0.11.6
2020-02-14 21:49:21 +01:00
Jan Dittberner cfc7d46adc Merge branch 'hotfix/0.11.6' into production 2020-02-14 21:38:04 +01:00
Jan Dittberner 20d864d9d1 Update dependencies
This commit updates the dependencies to versions that are know to work
on Debian Stretch.
2020-02-14 21:37:28 +01:00
Jan Dittberner e487dad026 Improve settings
The commit removes the non-existing sys.path import, simplifies the
condition in the show_debug_toolbar function and defines ALLOWED_HOSTS
for the test environment.
2019-07-05 21:25:31 +02:00
Jan Dittberner 977189c263 Update and improve docker image
This commit updates the docker image to be based on Debian 10 Buster.
The startup script waits until the database container becomes available.
Needed dependencies for building the PostgreSQL driver were added to the
docker image.
2019-07-05 21:23:24 +02:00
Jan Dittberner e36a8baedf Update dependencies 2019-07-05 21:22:49 +02:00
Jan Dittberner 3d18392b67 Fix tests for Python 3
- drop Python 2 __future__ imports
- fix tests to handle new Django and Python 3 module names
- reformat changed files with black
2019-01-30 21:27:25 +01:00
Jan Dittberner ddec6b4184 Use gnuviechadmin.settings
Specific settings have been removed, they are now triggerd by the
GVA_ENVIRONMENT variable.
2019-01-30 21:08:14 +01:00
Jan Dittberner 96a8e0e995 Update dependencies, use Python 3.6 2019-01-30 21:07:37 +01:00
Jan Dittberner 10a83d36f7 Fix locale support 2018-12-26 14:51:34 +01:00
Jan Dittberner 24009bff3e Set version to 0.12.0-alpha 2018-12-26 14:51:03 +01:00
Jan Dittberner c3e0506133 Update dependencies 2018-12-26 14:50:20 +01:00
Jan Dittberner 6f5c0a1b7c Use custom SHOW_TOOLBAR_CALLBACK 2018-12-26 14:49:56 +01:00
Jan Dittberner 6a982f8db2 Release hotfix 0.11.5 0.11.5
-----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCgAyFiEEKHuXKkUYdvdO9493DXkdyNc3wdkFAlwjdWsUHGphbkBkaXR0
 YmVybmVyLmluZm8ACgkQDXkdyNc3wdlVYAf/Y2AQsMQwp/MYht+xse2tznRVHPid
 XVDj8urrvW/Me7ugcuVdtIoOa1M+sc/8MGhpHWBzp92qAqpkQwkhTZZovaselLzq
 00+cf9HjNdUG+gEOW5eGBP0O0iN7bd/p1HqnmLtGEAx3YoKe4z2YHAl59Nb2jWoV
 9UiohbSK7+4fThC8r2Hj2zPmwnQ3t5QFLEWIp8xyvF+DQ3zuxXOoZlBK+9VR676j
 FxHox9eQ4iJpswlOzYDfS1nGzfVixI0cCvRuZeM1sHWteKVJrqOzNjKAAMi47T+v
 Jqq92EpLUFCsRxH+d5yvhLgNX6BpvWPtTDzd/SO6G+K4l/1whwWU//wG+g==
 =5PHe
 -----END PGP SIGNATURE-----

Merge tag '0.11.5'

Release hotfix 0.11.5 0.11.5
2018-12-26 13:35:55 +01:00
Jan Dittberner bfcabe664f Merge branch 'hotfix/0.11.5' into production 2018-12-26 13:34:48 +01:00
Jan Dittberner 271421cdf8 Set version number 2018-12-26 13:33:36 +01:00
Jan Dittberner 71aad5e078 Remove Xing from settings and templates
Xing canceled API access for us.
2018-12-26 13:28:25 +01:00
Jan Dittberner 6cebd80c89 Started port to Django 2.1, Python 3, Docker
This commit is a rough port to Django 2.1, Python 3 and a Docker based local
development setup. Tests fail/error but migrations and the web frontend are
already runnable. Task queue functionality is untested and translations seem to
have trouble.
2018-11-19 23:28:40 +01:00
Jan Dittberner adc57657dd Use pipenv for requirements 2018-11-17 20:07:29 +01:00
Jan Dittberner c676415c97 Update vagrant setup to stretch64 with LXC 2018-08-10 11:57:00 +02:00
Jan Dittberner 40c07745d2 Hotfix Release 0.11.4
-----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEKHuXKkUYdvdO9493DXkdyNc3wdkFAlhnrVsACgkQDXkdyNc3
 wdnfNAgAn7x1rlKR2RynhUY8Xdy9qDLTmJHFGdsYUR5m92VftcE7LDnvrZBNa26T
 kdprjxsA8xOfUGlX5BVFbY4FvFORuJUj8TP3NMUcJlL726dWWS0a8FKif9bLgtx4
 Ccca1DJDIFM72fniNyA6jxbNNvftQtEDohXiwzUE8IP932vgPr2tB55yoaZSVoUd
 El3yl1IZWVX8F4G/HyrCqO1BPTxmDbDJIiTNwMNrx1Hg4NZHWCzufFIcNrfkGqHI
 0LPxnHn6RAdxKFWxXi8JanHR91fosnpCLwLqWIkSskdKiStEg4FfRUffAtIDFoHa
 g0cwuBKwedmcibQLgTvekI2W0P/XGg==
 =I6aI
 -----END PGP SIGNATURE-----

Merge tag '0.11.4'

Hotfix Release 0.11.4

* tag '0.11.4':
  Fix wrong tag in password reset done template
2016-12-31 14:06:39 +01:00
Jan Dittberner 8f4c6d5696 Merge branch 'hotfix/0.11.4' into production
* hotfix/0.11.4:
  Fix wrong tag in password reset done template
2016-12-31 14:06:22 +01:00
Jan Dittberner e8bdf3fec1 Fix wrong tag in password reset done template 2016-12-31 14:03:57 +01:00
Jan Dittberner 4eb135eeb9 Add hosting package data example 2016-09-25 17:32:25 +02:00
Jan Dittberner 108f0e85bf Protect /etc/salt/grains
Make sure that the permissions of /etc/salt/grains only allow access for the
root user.
2016-09-25 17:27:42 +02:00
Jan Dittberner 36d082006b Improve TaskResult admin view
Provide a better presentation of TaskResult instances by specifying the
list_display fields and allowing to filter finished and unfinished tasks.
2016-09-25 16:36:31 +02:00
Jan Dittberner 150c9111ca Ignore PyCharm files 2016-09-25 01:10:45 +02:00
Jan Dittberner 89011b155a Improve vagrant setup
Install python-cryptography from jessie-backports and remove
autogenerated comments from Vagrantfile.
2016-09-24 23:54:57 +02:00
Jan Dittberner 5dc3549896 Improve documentation
This commit adds a lot of documentation including block diagramms for
message flows.
2016-09-24 21:57:28 +02:00
Jan Dittberner 09cfc6a373 Update Sphinx, bpython and cursies to latest versions 2016-02-01 22:31:34 +00:00
Jan Dittberner 3c5d02776a Update Django and gvacommon dependencies
This commit updates the Django dependency version to 1.9.2 and gvacommon
to 0.3.0 that provides gvacommon.settings_utils.get_env_variable. The
gnuviechadmin.settings.base module now uses this implementation instead
of an own copy and the corresponding test has been removed too.
2016-02-01 22:27:05 +00:00
Jan Dittberner 6c606034b3 Add docstrings from gvaldap settings 2016-01-31 23:22:07 +01:00
Jan Dittberner 3d95a9f61a Switch result backend to redis
The AMQP result backend proved as impractical, this commit switches to
redis instead. The redis server is setup on the webinterface host but
can be configured on another host.
2016-01-31 21:50:49 +01:00
Jan Dittberner 9d843c920a Add docstring to gnuviechadmin.settings.base 2016-01-31 21:50:11 +01:00
Jan Dittberner cd696ceb1f Fix flake8 finding 2016-01-31 21:50:11 +01:00
Jan Dittberner f3b76a09b7 Add code quality requirements 2016-01-31 21:50:11 +01:00
Jan Dittberner 07b0eb6981 Update celery dependency 2016-01-31 21:50:11 +01:00
Jan Dittberner eda20937dc Use separate test vhost for celery queues 2016-01-31 21:46:14 +01:00
Jan Dittberner e0449148a7 Move salt states and pillar data to separate repository 2016-01-31 21:45:06 +01:00
Jan Dittberner 6147a90066 Improve salt setup
This commit improves the salt setup of the Vagrant box:
- Salt output is reduced to log level warning
- Hosts entries are created for the internal IPs of all planned gva
  component VMs
- .bashrc and a .bash_functions sourced from it are now managed for the
  vagrant user
- the VM name has been changed to gva.local
- recent salt versions do not depend on m2crypto anymore, therefore it
  is now installed before x509certificate functions are called
- the rabbitmq_vhost for gva is now setup before any users are created
  because the previous implementation was broken with recent salt
  versions
- the gnuviechadmin-locale-data-compile step has been simplified because
  Django 1.9's compilemessages takes care of recursive .mo file
  compilation
- pillar data has been separated by role (especially queue permissions
  and credentials)
- salt configuration is now unified with gvaldap
2016-01-29 22:42:45 +01:00
Jan Dittberner f1f0e35ea1 Update documentation copyright years 2016-01-29 17:26:23 +01:00
Jan Dittberner a03a00e61b Add private network for inter VM communication 2016-01-29 16:52:14 +01:00
Jan Dittberner 2018520646 Start changelog for next release
This commit updates the changelog, switches to git code browsing for the
release links and uses correct semantic versioning.
2016-01-29 14:21:43 +00:00
Jan Dittberner 41fbb58def Switch to AGPLv3+ licensing 2016-01-29 14:53:12 +01:00
Jan Dittberner 5b48a3f2db Use gvacommon from own repository
This commit removes the included gvacommon copy. Gvacommon has its own
development repository and is now added as a dependency via
requirements/base.txt.
2016-01-29 13:26:18 +00:00
Jan Dittberner 37b18a17af Update German translation
This commit updates the German translation files and adds missing
translations.
2016-01-29 11:07:41 +01:00
Jan Dittberner e7006ac4a6 Fix encoding name
This commit fixes the encoding specification of
osusers.tests.test_models.
2016-01-29 10:04:59 +00:00
Jan Dittberner 0a0524f1f0 Add tests for userdbs.views.ChangeDatabaseUserPassword
This commit adds tests for the ChangeDatabaseUserPassword view.
2016-01-29 10:03:24 +00:00
Jan Dittberner 1f700fc06a Add tests for userdbs.views.DeleteUserDatabase
This commit adds tests for the DeleteUserDatabase view and improves the
grammar of flash messages of the userdbs.views module.
2016-01-29 09:40:14 +00:00
Jan Dittberner e6c38b632b Add test for userdbs.views.AddUserDatabase
This commit adds tests for userdbs.views.AddUserDatabase, the view
itself has been modified so that it is only reachable when the hosting
package actually has database options available.
2016-01-28 16:17:50 +01:00
Jan Dittberner e9fc8b7f89 Push coverage for osusers to 100% 2016-01-28 13:44:29 +00:00
Jan Dittberner a8e28fd595 Update system during provisioning 2016-01-26 13:24:22 +01:00
Jan Dittberner ed0a93bb3d Update dependencies
- Update to Django 1.9.1, crispy-forms 1.6.0, kombu 3.0.33, requests
  2.9.1 and snowballstemmer 1.2.1
2016-01-09 14:47:37 +00:00
Jan Dittberner de501cfdde Fix Django deprecation warning
Django 1.9 deprecates passing a context directly to the render function
in template loader. This commit creates a proper template rendering
context before rendering the mails sent from the contact form.
2016-01-09 14:46:04 +00:00
Jan Dittberner b8893e92d7 Add timestamps to task result model 2016-01-09 14:26:52 +00:00
Jan Dittberner 6a6009e7f2 Fix template error in passwort reset response 2015-12-26 12:29:22 +01:00
Jan Dittberner 085b126416 Update to Django 1.9
- update all dependencies
- fix deprecation warnings and errors for Django 1.9 compatibility
2015-12-19 20:11:23 +01:00
Jan Dittberner 1b30b1a38c Define logging for tests 2015-12-07 00:24:23 +00:00
Jan Dittberner c9a9fa11b2 Refactor userdbs app to use signals
This commit isolates the celery task invocations of the userdbs app into
signal handlers. All celery interaction is now asynchronously handled in
userdbs.signals.
2015-12-07 00:23:07 +00:00
Jan Dittberner 1649e4592e Add tests for userdbs app
This commit adds a set of unit tests for the userdbs app. Some tests
will fail because a refactoring to signals comes with the next commit.
2015-12-07 00:22:13 +00:00
Jan Dittberner e96aac82fc Add tests for taskresults app
This commit adds tests for the taskresults management command
fetch_taskresults and completes the test coverage for
taskresults.models.
2015-12-06 18:47:11 +01:00
Jan Dittberner 4e54b6fcc5 Add osusers.views tests
This commit adds tests for the osusers.views module. An incompatibility
with Django 1.8 in EditSshPublicKeyComment has been fixed.
2015-12-06 17:49:10 +01:00
Jan Dittberner 28ff099df9 Improve osusers.models coverage
This commit adds tests for more corner cases of
SshPublicKeyManager.parse_keytext to raise the test coverage to 100%.
The method now handles invalid keys more thoroughly.
2015-12-06 17:47:27 +01:00
Jan Dittberner 8616b2d6c9 Add tests for osusers.forms
This commit adds test classes for osusers.forms in
osusers.tests.test_forms.
2015-12-06 15:35:23 +01:00
Jan Dittberner 4f39c0d2c4 Add tests for osusers.admin
This commit raises the test coverage for osusers.admin to 100% by adding
tests for UserAdmin, GroupAdmin, SshPublicKeyCreationForm and
SshPublicKeyAdmin. The commit adds a refactoring TODO to
SshPublicKeyAdmin.perform_delete_selected because the asynchronous
background task should be launched from a signal handler.
2015-12-05 22:23:25 +00:00
Jan Dittberner fb1f31a9bc Fix flake8 warnings
This commit fixes all warnings created by flake8 by removing unused
imports and variable assignments. Some wrongly indented lines are now
indented correctly.
2015-12-05 13:47:41 +00:00
Jan Dittberner 30600ce107 Add tests for managemails.views
This commit adds a test suite for the views defined in
managemails.views. One issue discovered when writing tests is fixed by
checking the request method in CreateMailbox.dispatch.
2015-11-28 19:01:52 +00:00
Jan Dittberner 6533205479 Add TODO comments for mailbox task calls 2015-11-28 19:01:10 +00:00
Jan Dittberner f2c3f64a87 Use MD5PasswordHasher for tests
This commit changes the password hasher for test runs to the
MD5PasswordHasher to speed up password hashing during test runs.
2015-11-28 19:00:03 +00:00
Jan Dittberner 1cfd4327da Add tests for managemails.models
This commit adds tests for managemails.models to improve the test
coverage of that model. There are some changes to the classes in
managemails.models too:

- add a method create_mailbox to MailboxManager
- properly handle uncommited mailaddresses in MailAddress.set_mailbox
  and MailAddress.set_forward_addresses
2015-11-28 14:07:34 +00:00
Jan Dittberner 03a7dc0320 Add test for managemails.forms
This commit adds tests for managemails.forms. A refactoring TODO is
added to MailAddressFieldMixin and pragma: no cover has been added to
code paths not reachable if no new constants are added to the
MAILBOX_OR_FORWARDS constant array.
2015-11-22 18:41:45 +00:00
Jan Dittberner 78f54d0c92 Add QA tool config to setup.cfg
This commit adds configuration for coverage, pep8 and flake8 to
setup.cfg. The .coveragerc is not needed anymore and is removed.
2015-11-22 18:40:40 +00:00
Jan Dittberner 28fc535f9e Add tests for gvawebcore
This commit adds tests for gvawebcore.forms and gvawebcore.views.
2015-11-22 14:43:02 +00:00
Jan Dittberner b11055807f Clean PEP8 violations 2015-11-22 14:03:47 +00:00
Jan Dittberner be0531ec30 Add test for gnuviechadmin.celery
This commit adds a refactoring for gnuviechadmin.celery to make the
installed apps detection testable. The test is added in
gnuviechadmin.tests.test_celery. Debug code in gnuviechadmin.urls is no
excluded from coverage reporting.
2015-11-22 14:31:04 +01:00
Jan Dittberner 7bcb0d3100 Add tests for gnuviechadmin.context_processors
This commit adds new tests for the gnuviechadmin.context_processors
module. The module gnuviechadmin.tests has been moved into a separate
directory for a more clear structure.
2015-11-22 13:13:42 +00:00
Jan Dittberner de0f3b8ca1 Add translations for domains.models
addresses #17
2015-11-08 12:14:53 +01:00
Jan Dittberner 337947f50c Update documentation
This commit adds documentation how to setup PowerDNS to use the
gnuviechadmin DNS schema. The queries are provided in a PowerDNS
configuration file.

Addresses #17
2015-11-07 22:17:43 +01:00
Jan Dittberner c058cc7b1d Improve DNS table models
This commit adds Meta information and __str__ methods  to all DNS table
models. The new methods are now covered with new tests. The new
constants DNS_DOMAIN_METADATA_KINDS and DNS_TSIG_KEY_ALGORITHMS are
defined and used in the DNSDomainMetadata and DNSTSIGKey models. A
matching database schema migration is added.

Addresses #17
2015-11-07 16:10:38 +00:00
Jan Dittberner 1df2534cf3 Add DNS models
This commit add model classes closely matching the tables defined in
PowerDNS' schema as described at
https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/.

The commit includes the model definitions a schema migration including
PostgreSQL specific CHECK constraints and the registration in the Django
admin interface.

addresses #17
2015-11-05 20:54:21 +00:00
Jan Dittberner 8e954a1a8c Update to Django 1.8.6 2015-11-05 19:18:03 +01:00
Jan Dittberner 64b4302b87 Set vim as default editor
Use the alternatives system to set vim as default editor.
2015-10-25 18:30:27 +01:00
Jan Dittberner fbfd3cf41b Add tests for domains.views
This commit adds a test class to test the CreateHostingDomain view in
domains.views.
2015-10-25 17:30:15 +00:00
Jan Dittberner f5759f3194 Add tests for domains app
Add missing tests for domains.forms and domains.models.
2015-10-15 19:50:18 +00:00
Jan Dittberner 7d7a8941c3 enable line numbers in vim 2015-10-13 22:31:27 +02:00
Jan Dittberner 2de53757df improve contact_form test coverage 2015-10-13 22:31:20 +02:00
Jan Dittberner e51d202abd start test implementation for contact_form 2015-10-12 22:07:25 +00:00
Jan Dittberner c5d9673ac3 remove unnecessary imports 2015-10-12 20:51:03 +02:00
Jan Dittberner 084dd5ba8d add unit tests for dashboard app 2015-10-12 18:43:52 +00:00
Jan Dittberner 660ffa9de9 bump version to new development version 2015-10-12 18:42:14 +00:00
Jan Dittberner d5bba7a22d asynchronous refactoring
- don't execute celery tasks directly
- introduce optional parameters to fileserver tasks to allow chaining
- handle user/group/key create and delete tasks in new osusers.signals
  class
- adapt unit tests
- change TaskResults model to store the task signatures
- generalize the local settings' logging configuration
2015-10-12 00:23:31 +02:00
Jan Dittberner bcfea10e6f add simplejson to make task serialization work 2015-10-11 23:17:21 +02:00
Jan Dittberner 4f36c21d5b add host alias mq 2015-10-11 16:38:42 +02:00
Jan Dittberner 04871bb488 setup vimrc file for vagrant user 2015-10-11 15:38:45 +02:00
Jan Dittberner 8ebb5cad6a bump dependency versions, fix tests and deprecation warnings 2015-10-11 15:30:23 +02:00
Jan Dittberner 68170f7576 enable rabbitmq management and add admin permissions
- allow database creation for gnuviechadmin user in local deployments to
  allow test runs
- set administrator tag for gnuviechadmin user in rabbitmq
- add all permissions on gnuviechadmin vhost to gnuviechadmin user
- enable rabbitmq management plugin
2015-10-11 15:28:23 +02:00
Jan Dittberner 3270b43578 forward rabbitmq webadmin port from vagrant box 2015-10-11 15:27:46 +02:00
Jan Dittberner 5fe414133e make settings configurable via pillar, default to local 2015-10-11 14:11:11 +02:00
Jan Dittberner 5578647f33 fix locale compilation, use variables for paths
- install gettext
- define and use variables checkout, home and appdir
2015-10-11 14:01:12 +02:00
Jan Dittberner 6a0f88d7d4 manage screenrc and set hostname in vagrant box 2015-10-11 12:02:22 +02:00
Jan Dittberner 33338af352 finish vagrant configuration
- ignore collected assets
- setup virtualenv and environment variables
- import additional salt state modules
2015-10-04 23:02:04 +02:00
Jan Dittberner b07ab0a14b add PostgreSQL database and message queues to vagrant box 2015-10-04 20:18:44 +02:00
Jan Dittberner 3c6b779c44 setup default nginx ssl/security configuration for vagrant 2015-10-04 19:32:42 +02:00
Jan Dittberner 18ae1e15f4 setup vagrant box roles and nginx package 2015-10-04 19:00:46 +02:00
Jan Dittberner 6f9b17dc49 setup salt provisioning for vagrant 2015-10-04 14:20:44 +02:00
Jan Dittberner 11b1befa1b initial Vagrantfile 2015-10-04 12:08:15 +02:00
Jan Dittberner 1aa51cf61e release 0.11.3
- bug fixes for ssh public key handling
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJU6OPkAAoJEA15HcjXN8HZEPoH/02qF9W3E8Y55T07Re1sXwHv
 qjx5lFMduMBIC3IsVSudpimKP2ds3rbO/Q+l3kN2nTFR3uHdKXXM48FlpIqwINL2
 CJimvHh1PxkuqsFN6D2esGN079m/9VP0m3UMydX2QKbdkqQOBWO1CwOrUcL2pM5u
 iKxYeqD6NGTtrPFz5bRRlBGtDRRWAChvUfja1sIHcOEa4KYlcI3E6qaKJ5mNTOhk
 MfQfu7MoT2cUVhgBk2riGHnG4IQzFi1es/s1v2YWsg1ZfsBjWtYZthBw9KlOyS8u
 Yt+AQK8VmX/Usb6pUojHd/9l2o+/fJVVnZEI3e9HQaEhWlBD3Z1ncA8dwfkWlJg=
 =8lUx
 -----END PGP SIGNATURE-----

Merge tag '0.11.3'

release 0.11.3

- bug fixes for ssh public key handling

* tag '0.11.3':
  bump version number, add release version to changelog
2015-02-21 21:00:43 +01:00
Jan Dittberner c5962632d2 Merge branch 'release/0.11.3' into production
* release/0.11.3:
  bump version number, add release version to changelog
  fix broken ssh public key handling
  add appropriate filtering for SSH key list
2015-02-21 21:00:14 +01:00
Jan Dittberner 4c81502b8e bump version number, add release version to changelog 2015-02-21 20:59:09 +01:00
Jan Dittberner 25b5b82a06 fix broken ssh public key handling
- make sure that AddSshPublicKeyForm does not try to parse the key if it is
  None
- split the key text into a maximum of 3 parts to allow whitespace in comments
- update changelog
2015-02-21 20:57:18 +01:00
Jan Dittberner dd38edd498 add appropriate filtering for SSH key list
- fix osusers.views.ListSshPublicKeys
- add changelog entry
2015-02-21 20:30:15 +01:00
Jan Dittberner 13160b522d release 0.11.2
- mailforward setup bugfix
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJU1JWpAAoJEA15HcjXN8HZaOEIAIZCdTf6sbN91MZPIBRKPoau
 Jzki+SIJpFs9v5mJLJSWw6kf6cDe/XME399365Mfw+lTsu1eCcMbvoNo1F2I/XRE
 xe+KCVibVMH80qOZijrjJ7o8yG9vDC5UDU3Tzb/qS5GH7RNwFS76PVe/GDF0wgYh
 nZEU2IbJl1gHfVbNUmW5XU09pgT2lx24qK2MzDrjco5B2atHgDMjFIz6ycdnEm6f
 F+jQ+muX/803g3mLnSLD8Vid12J9+ugvgbw/km3bvGY4MS18VhwXP88ghmbM9iP4
 Om/defjWK0Mufmyb6Sehu/S4Xt6C+vI9hpm7CP4bBsZ/D9liSRpB3+xpTOUYswA=
 =RVpR
 -----END PGP SIGNATURE-----

Merge tag '0.11.2'

release 0.11.2

- mailforward setup bugfix

* tag '0.11.2':
  bump version number, add release to changelog
2015-02-06 11:21:34 +01:00
Jan Dittberner a298548244 Merge branch 'release/0.11.2' into production
* release/0.11.2:
  bump version number, add release to changelog
  fix mail forwarding setup bug
  improve documentation
2015-02-06 11:21:12 +01:00
Jan Dittberner 9cab636351 bump version number, add release to changelog 2015-02-06 11:20:47 +01:00
Jan Dittberner 2af30d6148 fix mail forwarding setup bug
- fix wrong variable name in
  managemails.models.MailAddress.set_forward_addresses and typo in
  managemails.forms.EditMailAddressForm
2015-02-06 11:17:03 +01:00
Jan Dittberner 78a11055f3 improve documentation
- add better README.rst
- improve structure of docs/index.rst
- add some words about deployment
- remove old implemented ideas and add some new ideas
2015-02-04 00:48:35 +01:00
Jan Dittberner f154a2efac release 0.11.1
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUzpiDAAoJEA15HcjXN8HZ9wQH/isO/WnSUJJfQCaO7nxPXJOW
 z7Uq0hRyk91nnvSY5sGJRkx5eO3DEYrf54bOSiykDcAR6hWVixs+xTFTc/CahpCL
 i9i9W/MZ/Ae3LkrF653QtOS/+bnBx1V9B9Yr0BnqpSev2KcRr9/nMPIeklB51dpV
 ub40c4ZnReHadUZaTfKptecie4LygU7s/dDKcyyUKN6yvHc4tyQfvm0J0ldRtAs6
 fKQizNXjAhskMyNVgqXGc6K0dpoBkJBTf7C48uMaLpem4RChPdUV0FnUlqaqnZWy
 HQ3ttCASt4QxH1Nw/ZG4iDNeGvnEogMm9Rch4vkkBKsxs9kZtlTI7iHUTUbgf7k=
 =6c9Z
 -----END PGP SIGNATURE-----

Merge tag '0.11.1'

release 0.11.1

* tag '0.11.1':
  bump version number, add release to changelog
2015-02-01 22:20:20 +01:00
Jan Dittberner bedd48dedc Merge branch 'release/0.11.1' into production
* release/0.11.1:
  bump version number, add release to changelog
  add version number to gnuviechadmin
  enable translations for contact form
2015-02-01 22:19:45 +01:00
Jan Dittberner b5714f2af3 bump version number, add release to changelog 2015-02-01 22:19:18 +01:00
Jan Dittberner 251e8a54f6 add version number to gnuviechadmin
- add __version__ to gnuviechadmin/__init__.py
- change docs/conf.py to use version number from gnuviechadmin
- add gnuviechadmin.context_processors.version_info to add
  gnuviechadmin_version to template context
- add version and technology links to templates/base.html footer
- add CSS styles for footer formatting
2015-02-01 22:15:40 +01:00
Jan Dittberner 1bee80044c enable translations for contact form 2015-02-01 20:58:53 +01:00
Jan Dittberner 8c30ec697d release 0.11.0
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUzntVAAoJEA15HcjXN8HZABwIAI93Y531nuMnQ6MsA9sTpPqB
 ovkDZVqu/qUHB79M0ta45tnXQgyjRhChYxUQiSg8APg0p2xhA2BMOcpdDrljfgFA
 IHPug+7h5//5dqCpqwCx5L3wOIIwwnjRFgsU9T5vdVKFMsvQUwpry1a7a/ZqL27w
 9syJ2IuvcVJb1IjjMA28+TNw/3Yh+ESRsZz9R/JZ1NVELDqmExnoy+0BsLc9FYRM
 gKOsn0TKbmSF4QsKBwDJwRVZcKXuk7yGj+AtvwupldIznorc7GRtByk1BGK/7Pyw
 WqvbNO3Mm5cdwXsC/md3bG+ShteIDLqBWq1HTyt19OxZF8OxGsHKwzRfd8tLDAE=
 =2ZBC
 -----END PGP SIGNATURE-----

Merge tag '0.11.0'

release 0.11.0

* tag '0.11.0':
  update docs version, add release to changelog
2015-02-01 20:15:41 +01:00
Jan Dittberner 11222c584d Merge branch 'release/0.11.0' into production
* release/0.11.0:
  update docs version, add release to changelog
  fix tests
  add icons to top level navigation
  add contact_form link in top navigation
  add context processing for contact_form views
  define DEFAULT_FROM_EMAIL in production settings
  implement contact form
  add imprint as flatpage
  fix issues with changed URLs
  add new german translation strings
  add new view CustomerHostingPackageList
  configure local logging
  mark active menu item as active
  add links to webmail, phpmyadmin and phppgadmin
2015-02-01 20:15:22 +01:00
Jan Dittberner 83a67a9e37 update docs version, add release to changelog 2015-02-01 20:15:00 +01:00
Jan Dittberner e913b1f771 fix tests 2015-02-01 20:12:23 +01:00
Jan Dittberner e87e4ca268 add icons to top level navigation 2015-02-01 19:39:09 +01:00
Jan Dittberner 52b6dd5845 add contact_form link in top navigation
- add contact_form URLs to gnuviechadmin.urls
- set href of contact link to 'contact_form'
2015-02-01 19:37:13 +01:00
Jan Dittberner f9e4e67cf6 add context processing for contact_form views 2015-02-01 19:34:41 +01:00
Jan Dittberner 42f3ed7f06 define DEFAULT_FROM_EMAIL in production settings 2015-02-01 19:34:12 +01:00
Jan Dittberner 385838580b implement contact form
- implement contact_form.forms.ContactForm
- implement contact_form.views.ContactFormView and
  contact_form.views.ContactSuccessView
- add new URL patterns 'contact_form' and 'contact_success' in
  contact_form.urls
- add contact_form templates base.html, contact_form.html, contact_form.txt,
  contact_form_subject.txt and contact_success.html
- add german translation for new strings
- add contact_form to .coveragerc
- add generated code documentation for contact_form app
- add changelog entry
2015-02-01 19:33:53 +01:00
Jan Dittberner 2b0f1f9f89 add imprint as flatpage
- add flatpages app to gnuviechadmin.settings.base.DJANGO_APPS
- add imprint handling to gnuviechadmin.context_processors.navigation, remove
  unused about page handling
- add URL 'imprint' to gnuviechadmin.urls
- replace link 'about' in template base.html with 'imprint'
- add templates for flatpages
- add german translation for imprint and contact navigation links
2015-02-01 16:39:01 +01:00
Jan Dittberner cea780a9b2 fix issues with changed URLs
- sort all_hosting_packages before hosting_packages
- allow _ in user names
- only display hosting link if user is authenticated
2015-02-01 15:14:26 +01:00
Jan Dittberner 5d19120bbf add new german translation strings 2015-02-01 15:09:10 +01:00
Jan Dittberner 2d4282194f add new view CustomerHostingPackageList
- create view hostingpackages.views.CustomerHostingPackageList to display a
  specific customer's hosting packages
- add docstring to view AllCustomerHostingPackageList
- add URL pattern 'hosting_packages' to hostingpackages.urls
- restructure hostingpackages URL patterns to remove useless parts
- add template hostingpackages/customerhostingpackage_list.html
- change links in template base.html to link to 'hosting_packages'
2015-02-01 15:04:04 +01:00
Jan Dittberner 3f07ddb062 configure local logging
- add log formatters 'verbose' and 'simple' to gnuviechadmin.settings.base
- add loggers and handler in gnuviechadmin.settings.local
2015-02-01 14:59:36 +01:00
Jan Dittberner 81b9bc163b mark active menu item as active 2015-02-01 14:58:32 +01:00
Jan Dittberner 210d1e122c add links to webmail, phpmyadmin and phppgadmin
- add new links dropdown to top navigation in template base.html
- add new settings GVA_LINK_WEBMAIL, GVA_LINK_PHPMYADMIN and
  GVA_LINK_PHPPGADMIN to gnuviechadmin.settings.base
- implement gnuviechadmin.context_processors.navigation to add links to
  request context of non-AJAX requests
- add generated documentation for gnuviechadmin.context_processors
- add changelog entry
2015-02-01 13:16:45 +01:00
Jan Dittberner 551fd0eeab release 0.10.0
- ssh keys feature and lots of code fixes
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUzYmxAAoJEA15HcjXN8HZqfgIAMVVCmzQBMc3Wh8MxO4FGsPL
 Dh75HzG+02bwnEz/dpz/Ugdfe8PbA6nEaQbNCvVspgGcYHQsS8hU341GI5/LHXpc
 l895c6S3C0j8XzIE2BSyyYmaE6Y11k1neNugVIIBWF60sTwUnO3MUYX5L8UmKtST
 qr+mUNria4OIRT5wADVYt52k8SeEuvBlKATHNSS3Ejrz+gJo8WH3NfCz0D7h3EJn
 pz8/GSy8XBnbVgrpPBjAqTfCEwzRZRFaM9KtypOs84fVGy7VKdpG9Tvnzg1JfBQm
 K3LoTvDtWyi/Z5SOhjq6lBzr/2GL0npp3nhTHOr0b9jjNRALqGFxi/69NcJ9AsQ=
 =Lazi
 -----END PGP SIGNATURE-----

Merge tag '0.10.0'

release 0.10.0

- ssh keys feature and lots of code fixes

* tag '0.10.0':
  update docs version, add release to changelog
2015-02-01 03:04:43 +01:00
Jan Dittberner 630d46b595 Merge branch 'release/0.10.0' into production
* release/0.10.0:
  update docs version, add release to changelog
  fix taskresults.tests
  add german translation for new strings
  add docstrings, restrict queryset of osusers.views
  implement caching for get_hosting_package
  add list, delete and edit comment of SSH public keys
  add view osusers.views.AddSshPublicKey
  repair osusers.tests.test_admin
  define readonly fields and own delete action for SSH key admin
  trigger tasks on SshPublicKey save and delete
  add administration form and admin class for SshPublicKey
  implement SshPublicKey model, manager and tests
  document HTML improvements
  use bootstrap alert classes for messages
  add api for set_file_ssh_authorized_keys task
  adapt comments to gvafile server side
  update Django version to 1.7.4
2015-02-01 03:03:58 +01:00
Jan Dittberner 08045cee4e update docs version, add release to changelog 2015-02-01 03:03:50 +01:00
Jan Dittberner 0e32d162f7 fix taskresults.tests 2015-02-01 03:01:29 +01:00
Jan Dittberner 0714d55902 Merge branch 'feature/ssh-keys'
* feature/ssh-keys:
  add german translation for new strings
  add docstrings, restrict queryset of osusers.views
  implement caching for get_hosting_package
  add list, delete and edit comment of SSH public keys
  add view osusers.views.AddSshPublicKey
  repair osusers.tests.test_admin
  define readonly fields and own delete action for SSH key admin
  trigger tasks on SshPublicKey save and delete
  add administration form and admin class for SshPublicKey
  implement SshPublicKey model, manager and tests
2015-02-01 02:30:43 +01:00
Jan Dittberner 01a0fa2fa4 add german translation for new strings 2015-02-01 02:30:30 +01:00
Jan Dittberner 5ad3ba1631 add docstrings, restrict queryset of osusers.views 2015-02-01 02:11:41 +01:00
Jan Dittberner 5e1f34c9d8 implement caching for get_hosting_package 2015-02-01 02:11:07 +01:00
Jan Dittberner 832a611602 add list, delete and edit comment of SSH public keys
- add sshkeys to hostingpackage detail view context
- implement new osusers.forms.EditSshPublicKeyCommentForm
- implement new views ListSshPublicKeys, DeleteSshPublicKey and
  EditSshPublicKeyComment
- add new URL patterns 'list_ssh_keys', 'edit_ssh_key_comment' and
  'delete_ssh_key'
- link from hosting package detail view to 'list_ssh_keys' when there are
  SSH keys assigned to the shown hosting package
- add new templates osusers/sshpublickey_list.html,
  osusers/sshpublickey_confirm_delete.html and
  osusers/sshpublickey_edit_comment
- add operating system user output to template
  osusers/sshpublickey_create.html
- add changelog entry
2015-02-01 01:55:09 +01:00
Jan Dittberner 0c7bb79109 add view osusers.views.AddSshPublicKey
- implement new form osusers.forms.AddSshPublicKeyForm
- move message texts from osusers.admin to osusers.forms
- add new view osusers.views.AddSshPublicKey
- add new URL patter 'add_ssh_key' to osusers.urls
- add new template osusers/sshpublickey_create.html
- link from hosting package detail template to 'add_ssh_key'
- add changelog entry for new feature
2015-02-01 00:44:31 +01:00
Jan Dittberner 79b460c4a6 repair osusers.tests.test_admin
- fix test code
- fix error in set_ldap_user_password stub
2015-02-01 00:08:04 +01:00
Jan Dittberner b993053d2a define readonly fields and own delete action for SSH key admin
- implement custom perform_delete_selected action for SshPublicKeyAdmin that
  ensures that the authorized_keys files of all affected users are rebuilt
  after deleting keys
- implement custom get_actions to replace the default delete_selected action
  with the custom perform_delete_selected
- define get_readonly_fields to make sure that the key algorithm and data
  cannot be changed
2015-02-01 00:08:04 +01:00
Jan Dittberner 7dd4c78345 trigger tasks on SshPublicKey save and delete
- implement save and delete methods in osusers.models.SshPublicKey that trigger
  set_file_ssh_authorized_keys
- add new test methods to osusers.tests.test_models.SshPublicKeyTest
2015-02-01 00:08:04 +01:00
Jan Dittberner 0080fe7e78 add administration form and admin class for SshPublicKey 2015-02-01 00:08:04 +01:00
Jan Dittberner 20359681db implement SshPublicKey model, manager and tests
- implement osusers.models.SshPublicKey and osusers.models.SshPublicKeyManager
- fix broken osusers.models.tests.test_models
- add new test classes SshPublicKeyManagerTest and SshPublicKeyTest
- add migration for SshPublicKey model
2015-02-01 00:07:56 +01:00
Jan Dittberner 9fa351f801 document HTML improvements 2015-01-31 14:29:07 +01:00
Jan Dittberner d921acd686 use bootstrap alert classes for messages 2015-01-31 13:30:48 +01:00
Jan Dittberner f0c8336708 add api for set_file_ssh_authorized_keys task 2015-01-29 23:05:16 +01:00
Jan Dittberner 33e78bcb69 adapt comments to gvafile server side 2015-01-29 21:03:55 +01:00
Jan Dittberner 99980767da update Django version to 1.7.4 2015-01-29 17:05:53 +01:00
Jan Dittberner 3b000b3d81 release 0.9.0
- implement adding websites with integration of gvaweb and gvafile tasks
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUx9WKAAoJEA15HcjXN8HZ2XgIANRNQCkTJ6OLjuleYzVdqqmj
 KET3wJ8D1ERWCVVMNebadFd0VH8oPlJrp4/BLiiH+CInSC83MslixIS2ftCB9bsl
 n38eywhCEuKvwW0y9JAN8U4z6xkodlWX7ke87q6D0JE3DyMp+gZkZx7zPlqppNzm
 UGGBWl05ouW5/9wVkn741uqwSrLUOZQCacahRZ+yZpmGTo25q442zmdwAOR9ECkr
 1wxWwV2VoOFu+DnUwafhfyEhKPokFr6UIIbHApF/LhhhwSds5G4fjLGMdkpxSZaf
 HLmKT06hickIXcSTu9RVFtXtw1Lgp9Z8xjmwE6Wnh0Pkg8yiR3vb6zlyBdg9iFo=
 =Ltav
 -----END PGP SIGNATURE-----

Merge tag '0.9.0'

release 0.9.0

- implement adding websites with integration of gvaweb and gvafile tasks

* tag '0.9.0':
  add release version in changelog, update conf.py
2015-01-27 19:14:40 +01:00
Jan Dittberner e718c472e8 Merge branch 'release/0.9.0' into production
* release/0.9.0:
  add release version in changelog, update conf.py
  add changelog entry
  mark bugs as major to include them in 0.7.0 changelog
  update translations, add new strings
  add code documentation for websites app
  implement websites.models.Website.delete
  implement website.models.Website.save
  implement domain name validation
  implement website deletion
  link from hostingpackage detail view to 'add_website'
  implement adding websites
  define User.is_sftp_user and fix minor template issues
  make manage.py executable
  add wildcard parameter to create_web_vhost_config task
  add django generated websites app
  add webtasks interface
  update to fileservertasks interface 0.4.0 version
  add new route 'web' for web server configuration
2015-01-27 19:13:59 +01:00
Jan Dittberner 35a784300f add release version in changelog, update conf.py 2015-01-27 19:13:41 +01:00
Jan Dittberner 020cca9bd3 Merge branch 'feature/website_setup'
* feature/website_setup:
  add changelog entry
  mark bugs as major to include them in 0.7.0 changelog
  update translations, add new strings
  add code documentation for websites app
  implement websites.models.Website.delete
  implement website.models.Website.save
  implement domain name validation
  implement website deletion
  link from hostingpackage detail view to 'add_website'
  implement adding websites
  define User.is_sftp_user and fix minor template issues
  make manage.py executable
  add wildcard parameter to create_web_vhost_config task
  add django generated websites app
  add webtasks interface
  update to fileservertasks interface 0.4.0 version
2015-01-27 19:12:04 +01:00
Jan Dittberner 8d3f9582ef add changelog entry 2015-01-27 19:09:46 +01:00
Jan Dittberner b92bb9ac9a mark bugs as major to include them in 0.7.0 changelog 2015-01-27 19:09:21 +01:00
Jan Dittberner 742f0d0e33 update translations, add new strings 2015-01-27 19:08:13 +01:00
Jan Dittberner 5322e00345 add code documentation for websites app 2015-01-27 18:51:04 +01:00
Jan Dittberner 1f485e6b29 implement websites.models.Website.delete
- implement delete method and let it call these tasks:
  - disable_web_vhost
  - delete_web_vhost_config
  - delete_file_website_hierarchy
  - delete_web_php_fpm_pool_config if this was the last website of the
    user
2015-01-27 18:42:07 +01:00
Jan Dittberner be1e7bd27f implement website.models.Website.save
- implement save method and let it call these tasks:
  - create_web_php_fpm_pool_config if the user has no website yet
  - create_file_website_hierarchy
  - create_web_vhost_config
  - enable_web_vhost
2015-01-27 18:40:22 +01:00
Jan Dittberner 7c9509c159 implement domain name validation
- implement domains.forms.relative_domain_validator
- use the validator for domain field validation in
  domains.forms.CreateHostingDomainForm
- use the validator for subdomain field validation in
  websites.forms.AddWebsiteForm
2015-01-27 16:41:44 +01:00
Jan Dittberner 7da5cfe406 implement website deletion
- implement websites.views.DeleteWebsite
- add URL pattern 'delete_website' to websites.urls
- add template website_confirm_delete.html
- add link from hostingpackage page to 'delete_website'
- add changelog entry
2015-01-27 16:26:10 +01:00
Jan Dittberner 5ad32e6894 link from hostingpackage detail view to 'add_website' 2015-01-26 22:53:57 +01:00
Jan Dittberner 711a96212c implement adding websites
- implement websites.models.Website
- add migration
- implement websites.views.AddWebsite
- implement websites.forms.AddWebsiteForm
- define URL pattern 'add_website' in websites.urls
- register Website model in websites.admin
- add templates websites/base.html and websites/website_create.html
- add german translation for new strings
- add website URLs to gnuviechadmin.urls
- add websites to INSTALLED_APPS
- add changelog entry
2015-01-26 22:49:16 +01:00
Jan Dittberner cff35dd408 define User.is_sftp_user and fix minor template issues 2015-01-26 21:49:22 +01:00
Jan Dittberner b98b05220f make manage.py executable 2015-01-26 21:45:27 +01:00
Jan Dittberner 7fbeb668da add wildcard parameter to create_web_vhost_config task 2015-01-26 21:36:24 +01:00
Jan Dittberner ba85ad8ad9 add django generated websites app 2015-01-26 21:00:52 +01:00
Jan Dittberner 57d4b128f5 add webtasks interface
- add webtasks interface code
- add webtasks to generated code documentation
- add webtasks and fileservertasks to INSTALLED_APPS
2015-01-26 20:58:43 +01:00
Jan Dittberner 24b4bab0b0 update to fileservertasks interface 0.4.0 version 2015-01-26 18:10:08 +01:00
Jan Dittberner 7360b33eca Merge commit 'd31c1d0fbf02bde5d4dc2be24762d872da64935f'
* commit 'd31c1d0fbf02bde5d4dc2be24762d872da64935f':
  add new route 'web' for web server configuration
2015-01-26 15:44:04 +01:00
Jan Dittberner d31c1d0fbf add new route 'web' for web server configuration 2015-01-26 15:43:05 +01:00
Jan Dittberner 5972560b77 release 0.8.0
This release provides new features to create and delete user databases and to
 set database user passwords.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUxjmhAAoJEA15HcjXN8HZub0H/0/x5dgb4MjbhCxGhfWNM/mU
 v5P0TKf1uNtzRPOEjEkqPd8omf0jX5E50QZcG4j0DSwzOyzokzrnFTLTEfVATikO
 YOj6QDEp1N8MrpYkJj6LQMm1G3ABfoDEbkxwymrRvMlft7ohvfHDCw9qRIJTqyM6
 mUy+kRGljrGMzaEMG4qLptWyWGHL+3tVLPoMtBLj9bzd9ItjYRvZ7rPQ9dvhHVHe
 gA6wLFF9DSZKqAMZGEPN2XpVg5b3QH2JSoqGVuhhlaxFVnj50QJVENfB3TCvU584
 zOK1wPZK+SwICShKQDnon6FuflusB/Li2ejjyOolYshgipRN2Hzrh+sFZoPozwc=
 =rSKu
 -----END PGP SIGNATURE-----

Merge tag '0.8.0'

release 0.8.0

This release provides new features to create and delete user databases and to
set database user passwords.

* tag '0.8.0':
  add release version in changelog, update conf.py
2015-01-26 13:57:10 +01:00
Jan Dittberner 3b248f650c Merge branch 'release/0.8.0' into production
* release/0.8.0:
  add release version in changelog, update conf.py
  add german translation for new strings
  implement user database deletion
  improve table layout on hosting package detail page
  implement database user password change
  link from hostingpackages details to add_userdatabase
  implement setup of new user databases
  add combined method for creating databases with users
  performance optimizations for hosting package detail view
  move HostingPackageAndCustomerMixin to gvawebcore.views
2015-01-26 13:56:15 +01:00
Jan Dittberner ec1796e269 add release version in changelog, update conf.py 2015-01-26 13:56:08 +01:00
Jan Dittberner 9c998509eb Merge branch 'feature/setup_userdbs'
* feature/setup_userdbs:
  add german translation for new strings
  implement user database deletion
  improve table layout on hosting package detail page
  implement database user password change
  link from hostingpackages details to add_userdatabase
  implement setup of new user databases
  add combined method for creating databases with users
  performance optimizations for hosting package detail view
  move HostingPackageAndCustomerMixin to gvawebcore.views
2015-01-26 13:53:02 +01:00
Jan Dittberner 065a97665b add german translation for new strings 2015-01-26 13:52:55 +01:00
Jan Dittberner 64e3f97330 implement user database deletion
- modify userdbs.models.UserDatabase.delete to perform deletion of database
  user if it has no other databases assigned
- implement userdbs.views.DeleteUserDatabase
- add URL pattern 'delete_userdatabase' to userdbs.urls
- add template userdbs/userdatabase_confirm_delete.html
- add link to 'delete_userdatabase' on hosting package detail page
- add changelog entry
2015-01-26 13:42:09 +01:00
Jan Dittberner d5eccafea7 improve table layout on hosting package detail page
- add CSS classes for table column width
- use same CSS class for same type of column in domain, mailbox and database
  tables
2015-01-26 13:38:26 +01:00
Jan Dittberner fd6449dff1 implement database user password change
- implement userdbs.forms.ChangeDatabaseUserPasswordForm
- implement userdbs.views.ChangeDatabaseUserPassword
- add URL pattern 'change_dbuser_password' to userdbs.urls
- add template userdbs/databaseuser_setpassword.html
- link from hostingpackage detail template to 'change_dbuser_password'
- add changelog entry
2015-01-26 12:39:42 +01:00
Jan Dittberner 486c07d27d link from hostingpackages details to add_userdatabase
- add database URLs to gnuviechadmin.urls
- add link in template hostingpackages/customerhostingpackage_detail.html
- add changelog entry for new feature
2015-01-26 12:07:56 +01:00
Jan Dittberner 0e1a84826d implement setup of new user databases
- implement userdbs.forms.AddUserDatabaseForm
- implement userdbs.views.AddUserDatabase
- add new URL pattern 'add_userdatabase' in userdbs.urls
- add templates userdbs/base.html and userdbs/userdatabase_create.html
- add generated code documentation for new modules
2015-01-26 12:06:03 +01:00
Jan Dittberner 2447f558e4 add combined method for creating databases with users
- implement userdbs.models.UserDatabaseManager.create_userdatabase_with_user to
  setup a new database with a new database user in one step
2015-01-26 12:05:07 +01:00
Jan Dittberner f3168ffdb7 performance optimizations for hosting package detail view
- prefetch database objects in CustomerHostingPackageDetails.get_context_data
- use prefetched data in template hostingpackage/customerhostingpackage_detail.html
- mention optimization in changelog
2015-01-26 12:04:43 +01:00
Jan Dittberner 638a6f6712 move HostingPackageAndCustomerMixin to gvawebcore.views 2015-01-26 10:33:01 +01:00
Jan Dittberner 7bc26b261c release 0.7.0
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUxV8cAAoJEA15HcjXN8HZZD4H/A5dWE9UnD0R9WdnnVuFex4r
 MA99O6+a3Vl8XXpZErSjFg37j9lZ1vRn7we+mXl0irxfnGqlCUtazACZbN+yfcbM
 f84b0xTOaid28ytbohJxJaPNm/CxejhRKpLieIr2hIWFuk/LK1fsm/9pkjifk80o
 KhS5q8jTchuy7v9juhrrGRwvKSHRY9daMyQbTo67KgK+ugTjIh+YIYF81tQiHPdq
 yPxRlpymSYtkUEieUOIXZhfKQUoZaaCd41xi3M68qGf3zRMJt2zTLHHjrQlz3ulD
 zDpj5FZidptGsbtiKZLxt32Kg85Zcs/zKxbEi8SNXQJQhLDRcPmEOOkpXHShmDk=
 =h92O
 -----END PGP SIGNATURE-----

Merge tag '0.7.0'

release 0.7.0

* tag '0.7.0':
  add release version in changelog, update conf.py
2015-01-25 22:24:50 +01:00
Jan Dittberner 82255ae140 Merge branch 'release/0.7.0' into production
* release/0.7.0: (35 commits)
  add release version in changelog, update conf.py
  add german translation for new strings
  link to mailaddress functionality
  implement mail address target editing
  implement mail address deletion
  add verbose name to MailAddress fields
  update to bootstrap 3.3.2
  implement managemails.Views.AddMailAddress
  add german translation for new strings
  add feature description and bugfixes to changelog
  implement adding options to hosting packages
  implement hosting package option choice view
  implement password change for mailboxes
  enable mailbox creation
  implement create_mailbox functionality
  add changelog entry for refactoring
  refactor osusers password forms
  implement new module gvawebcore to provide common code
  update german translation
  add feature remark in changelog, add domains code docs
  ...
2015-01-25 22:24:33 +01:00
Jan Dittberner 0e6f1b9f17 add release version in changelog, update conf.py 2015-01-25 22:24:10 +01:00
Jan Dittberner 3eda45150f Merge branch 'feature/mailaddress_setup'
* feature/mailaddress_setup:
  add german translation for new strings
  link to mailaddress functionality
  implement mail address target editing
  implement mail address deletion
  add verbose name to MailAddress fields
  update to bootstrap 3.3.2
  implement managemails.Views.AddMailAddress
2015-01-25 22:22:15 +01:00
Jan Dittberner 78728c59e6 add german translation for new strings 2015-01-25 22:22:09 +01:00
Jan Dittberner 682977277e link to mailaddress functionality 2015-01-25 22:13:11 +01:00
Jan Dittberner 5429055f0d implement mail address target editing
- extract common code into managemails.forms.MailAddressFieldMixin
- move code from forms into managemails.models.MailAddress
- implement managemails.models.MailboxManager.unused and unused_or_own
- implement managemails.forms.EditMailAddressForm
- add managemails.views.EditMailAddress
- add URL pattern 'edit_mailaddress' to managemails.urls
- add template managemails/mailaddress_edit.html
- add changelog entry
2015-01-25 22:12:03 +01:00
Jan Dittberner bebcad8c86 implement mail address deletion
- implement managemails.views.DeleteMailAddress
- add get_context_data to AddMailAddress to add customer to template context
- add URL pattern 'delete_mailaddress' to managemails.urls
- add template hostingpackages/customerhostingpackage_detail.html
- add entry to changelog
2015-01-25 19:03:58 +01:00
Jan Dittberner af27400077 add verbose name to MailAddress fields 2015-01-25 19:01:01 +01:00
Jan Dittberner f9ce3929f7 update to bootstrap 3.3.2 2015-01-25 18:54:07 +01:00
Jan Dittberner 1d69bb22dc implement managemails.Views.AddMailAddress
- implement managemails.forms.multiple_email_validator
- implement managemails.forms.AddMailAddressForm
- implement managemails.views.AddMailAddress
- add URL pattern 'add_mailaddress' to managemails.urls
- add template managemails/mailaddress_create.html
- add changelog entry
2015-01-25 18:20:51 +01:00
Jan Dittberner 3271690841 Merge branch 'feature/add_hosting_options'
* feature/add_hosting_options:
  add german translation for new strings
  add feature description and bugfixes to changelog
  implement adding options to hosting packages
  implement hosting package option choice view
2015-01-25 15:53:19 +01:00
Jan Dittberner fbb0755446 add german translation for new strings 2015-01-25 15:51:29 +01:00
Jan Dittberner e14be4a905 add feature description and bugfixes to changelog 2015-01-25 15:46:17 +01:00
Jan Dittberner 0fc823a305 implement adding options to hosting packages
- fix unique constraints on CustomerDiskSpaceOption and
  CustomerUserDatabaseOption to allow multiple options from the same template
  for hosting packages
- fix disk space calculation in CustomerHostingPackage
- implement hostingpackages forms AddDiskspaceOptionForm, AddMailboxOptionForm,
  AddUserDatabaseOptionForm
- implement hostingpackages.views.AddHostingOption
- add new URL pattern add_hosting_option to hostingpackages.urls
- add template hostingpackages/add_hosting_option.html
- link items on hostingpackages/customerhostingpackage_option_choices.html to
  add_hosting_option
2015-01-25 15:15:39 +01:00
Jan Dittberner 9815bd1f5b implement hosting package option choice view
- implement new hostingpackages.views.HostingOptionChoices
- add URL pattern 'hosting_option_choices' to hostingpackages.urls
- add template hostingpackages/customerhostingpackage_option_choices.html
- link from hostingpackages/customerhostingpackage_detail.html to
  'hosting_package_choices'
2015-01-25 14:04:32 +01:00
Jan Dittberner 353ea7ad90 Merge branch 'feature/mailaccount_setup'
* feature/mailaccount_setup:
  implement password change for mailboxes
  enable mailbox creation
  implement create_mailbox functionality
  add changelog entry for refactoring
  refactor osusers password forms
  implement new module gvawebcore to provide common code
2015-01-25 12:54:25 +01:00
Jan Dittberner 2e4efe7839 implement password change for mailboxes
- implement managemails.forms.ChangeMailboxPasswordForm
- extract code for determining hosting package and customer from URL into
  HostingPackageAndCustomerMixin
- implement managemails.views.ChangeMailboxPassword
- add new URL pattern 'change_mailbox_password' to managemails.urls
- add template managemails/mailbox_setpassword.html
- link from template hostingpackages/customerhostingpackage_detail.html to
  change_mailbox_password
- add german translation for new strings
- document new feature in changelog
2015-01-25 12:49:31 +01:00
Jan Dittberner d1119331d8 enable mailbox creation
- add managemails.urls to gnuviechadmin.urls
- add link to create_mailbox to customerhostingpackage_detail.html template
- document feature in changelog
2015-01-25 12:16:18 +01:00
Jan Dittberner 449af174ec implement create_mailbox functionality
- implement managemails.forms.CreateMailboxForm
- implement managemails.views.CreateMailbox
- add url pattern 'create_mailbox' to managemails.urls
- add templates managemails/base.html and managemails/mailbox_create.html
- add german translation
- add generated code documentation
2015-01-25 12:10:17 +01:00
Jan Dittberner 6cb61ea105 add changelog entry for refactoring 2015-01-25 12:08:30 +01:00
Jan Dittberner 2b989799ab refactor osusers password forms
- use PasswordModelFormMixin from gvawebcore instead of own implementation in
  ChangeOsUserPasswordForm
- change import for PASSWORD_MISMATCH_ERROR
2015-01-25 12:02:31 +01:00
Jan Dittberner 9883db6fa2 implement new module gvawebcore to provide common code
- add gvawebcore.forms.PasswordModelFormMixin
- add generated documentation
- add german translation
2015-01-25 12:00:30 +01:00
Jan Dittberner 1ab832b94a update german translation 2015-01-25 00:58:31 +01:00
Jan Dittberner c6bb05a6c3 Merge branch 'feature/customer_domains'
* feature/customer_domains:
  add feature remark in changelog, add domains code docs
  implement hosting domain creation
  add domain creation form and model code
  update changelog to mention the new feature
  add link hosting package list templates
  add new views to hostingpackages app
  setup template structure for hosting package
  add more properties to CustomerHostingPackage
  update to font-awesome 4.3.0
  add model features to hostingpackages
  add MailDomain.get_mailaddresses and mailaddresses property
  improve managemails app
  add generated documentation for domains app
  add admin site support for hosting domains
  implement model changes
2015-01-25 00:43:50 +01:00
Jan Dittberner 266598a43e add feature remark in changelog, add domains code docs 2015-01-25 00:43:10 +01:00
Jan Dittberner 1690cace4d implement hosting domain creation
- implement domains.views.CreateHostingDomain
- define new URL create_hosting_domain in domains.urls
- add domains app URLs to gnuviechadmin.urls
- add templates domains/base.html and domains/hostingdomain_create.html
- link from hostingpackage detail page to domain creation view
2015-01-25 00:40:43 +01:00
Jan Dittberner 8615394c2f add domain creation form and model code
- implement domains.forms.CreateHostingDomainForm
- implement domains.models.HostingDomainManager.create_for_hosting_package that
  takes care of creating the necessary database objects for hosting domains
  assigned to a hosting package
2015-01-25 00:38:42 +01:00
Jan Dittberner 110b3d03f2 Merge branch 'feature/admin_customer_list' into feature/customer_domains
* feature/admin_customer_list:
  update changelog to mention the new feature
  add link hosting package list templates
  add new views to hostingpackages app
2015-01-24 23:40:23 +01:00
Jan Dittberner 2b062edf68 update changelog to mention the new feature 2015-01-24 23:40:03 +01:00
Jan Dittberner bf91664f6e add link hosting package list templates
- add link to hosting package list for staff users in top navigation
- add new template hostingpackages/customerhostingpackage_admin_list.html
2015-01-24 23:37:20 +01:00
Jan Dittberner 4bffa5ec62 add new views to hostingpackages app
- rename CreateHostingPackage to CreateCustomerHostingPackage
- add new CreateHostingPackage that allows to select a customer
- rename CreateHostingPackageForm to CreateCustomerHostingPackageForm
- add new CreateHostingPackageForm that has a customer field
- add new URL pattern create_hosting_package, rename existing pattern to
  create_customer_hosting_package
- modify template dashboard/user_dashboard to use the correct URL name
2015-01-24 23:34:15 +01:00
Jan Dittberner 7991d2bf4f setup template structure for hosting package
- add panels for hosting package options, domains, mailboxes and databases
- list existing objects assigned to the hosting package
2015-01-24 22:33:09 +01:00
Jan Dittberner 0def7e3a7b add more properties to CustomerHostingPackage
- add get_hostingoptions method and property hostingoptions
- add get_package_space method to determine disk space provided by the
  hosting package itself
- add get_databases_flat and property databases to get a list of databases
  assigned to the hosting package
- add may_add_database to determine whether additional databases are allowed
  by the hosting package's options
2015-01-24 22:29:57 +01:00
Jan Dittberner 2c170ebcc1 update to font-awesome 4.3.0 2015-01-24 22:29:02 +01:00
Jan Dittberner 03e5c74d7a add model features to hostingpackages
- add properties mailboxes, used_mailbox_count, mailbox_count and
  may_add_mailbox to CustomerHostingPackage class
- use new properties in template dashboard/user_dashboard.html
2015-01-24 22:26:27 +01:00
Jan Dittberner 8a84c9660a add MailDomain.get_mailaddresses and mailaddresses property 2015-01-24 21:01:37 +01:00
Jan Dittberner e04132bd24 improve managemails app
- add managemails.apps to give a more meaningful title in the admin site
- add verbose names to MailAddressMailbox fields
- implement managemails.models.Mailbox.get_mailaddresses and a corresponding
  property mailaddresses
2015-01-24 20:58:20 +01:00
Jan Dittberner 47abaa6d62 add generated documentation for domains app 2015-01-24 19:25:58 +01:00
Jan Dittberner 75e4892835 add admin site support for hosting domains 2015-01-24 19:24:33 +01:00
Jan Dittberner 0c291f0510 implement model changes
- add new domains.apps.AppConfig to allow translatable app description for
  domains app
- link domains to a customer
- extract common functionality from domains.models.MailDomain into abstract
  domains.models.DomainBase
- add separate domains.models.HostingDomain to allow for generic external
  domains
- add new hostingpackages.models.CustomerHostingPackageDomain to assign hosting
  domains to hosting packages
2015-01-24 19:10:58 +01:00
Jan Dittberner a3e3e2a76f add missing german translations 2015-01-24 18:27:12 +01:00
Jan Dittberner a44689d9c4 release 0.6.0
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUw7trAAoJEA15HcjXN8HZ7CIIAKybBN8Cqp+AcQ+y231d+bQu
 FDNyhy6//VuJF2ma1Mcx+mVvySctQzJCOtDRqkR45R5TdvPMfmIxXQILvhoG2Awo
 xgebSZOxKHoPvS6NLyAZV6Gv6/DF1l4Y2wyKROYafkds5wIyV7iv2QO6wbOEZbkQ
 lAoHWUEi5RnLm9Z1KBc4sEERGpXwjmSqFCVw1jdHCFP8rHhklzwvrHjUzY0YKUSn
 q2zdpkwMKABR1TXOQ88hTS83iDXSgXdB5m4Dc+QBIM3bz7bSf97PHEkqMnwmQ0eQ
 XV673gXQczQySl6rMm8H4JqhxmA1f2rjWWXeA9WCYweqNOfQbksK9sqYDkDLNcs=
 =WyWZ
 -----END PGP SIGNATURE-----

Merge tag '0.6.0'

release 0.6.0

* tag '0.6.0':
  define version number, mark version in changelog
2015-01-24 16:34:08 +01:00
Jan Dittberner b27dfd5d68 Merge branch 'release/0.6.0' into production
* release/0.6.0: (32 commits)
  define version number, mark version in changelog
  plug users and hosting packages together
  implement CustomerHostingPackageDetails view
  introduce new settings for groups and upload server
  implement osusers.forms.ChangeOsUserPasswordForm
  refactor dashboard.views.UserDashboardView
  generate documentation for gvacommon.viewmixins
  implement viewmixins.StaffOrSelfLoginRequiredMixin
  create system user when creating a new hosting package
  fix some test issues
  incomplete create_hosting_package view
  fix issue with mailbox count calculation
  remove unused LogoutView and corresponding url pattern
  add docstrings to managemails.models
  add task stub for ldaptasks.tasks.set_ldap_user_password
  update changelog
  adapt documentation to changed module structure
  refactor osusers.tasks into fileservertasks and ldaptasks
  add a list of planned features and development ideas
  remove newline at EOF
  ...
2015-01-24 16:33:54 +01:00
Jan Dittberner 5583870caa define version number, mark version in changelog 2015-01-24 16:33:32 +01:00
Jan Dittberner f55886f1fe Merge branch 'feature/set_sftp_password'
* feature/set_sftp_password:
  plug users and hosting packages together
  implement CustomerHostingPackageDetails view
  introduce new settings for groups and upload server
  implement osusers.forms.ChangeOsUserPasswordForm
  refactor dashboard.views.UserDashboardView
  generate documentation for gvacommon.viewmixins
  implement viewmixins.StaffOrSelfLoginRequiredMixin
2015-01-24 16:32:12 +01:00
Jan Dittberner 150366a524 plug users and hosting packages together
- document new feature in changelog
- add autogenerated documentation for osusers.urls and osusers.views
- add osuser URLs to gnuviechadmin.urls
- implement get_absolute_url in hostingpackages.models.CustomerHostingPackage
- use set_ldap_user_password instead of create_ldap_user for existing OS users
  in osusers.models.User.set_password
- add URL pattern set_osuser_password in osusers.urls
- implement osusers.views.SetOsUserPassword to set the password of an existing
  operating system user
- link to hosting package detail view on user dashboard
- add template hostingpackages/customerhostingpackage_detail.html
- add template osusers/user_setpassword.html
2015-01-24 16:26:32 +01:00
Jan Dittberner 0d08d9876b implement CustomerHostingPackageDetails view 2015-01-24 16:25:18 +01:00
Jan Dittberner 0baee51d19 introduce new settings for groups and upload server 2015-01-24 16:22:09 +01:00
Jan Dittberner 68c0bfbb4e implement osusers.forms.ChangeOsUserPasswordForm
- implement new form for password changes
- use osusers.forms.PASSWORD_MISMATCH_ERROR in osusers.admin
- add autogenerated documentation
2015-01-24 16:21:47 +01:00
Jan Dittberner 3a9110dc30 refactor dashboard.views.UserDashboardView
- use gvacommon.viewmixins.StaffOrSelfLoginRequiredMixin instead of custom
  implementation
2015-01-24 16:12:23 +01:00
Jan Dittberner dd7a40a019 generate documentation for gvacommon.viewmixins 2015-01-24 15:42:20 +01:00
Jan Dittberner 6490b71c2b Merge commit '3c4d34cce56dfb75e0e4115c3938ce5b2e6efd83' into feature/set_sftp_password
* commit '3c4d34cce56dfb75e0e4115c3938ce5b2e6efd83':
  implement viewmixins.StaffOrSelfLoginRequiredMixin
2015-01-24 15:41:37 +01:00
Jan Dittberner 3c4d34cce5 implement viewmixins.StaffOrSelfLoginRequiredMixin 2015-01-24 15:38:08 +01:00
Jan Dittberner 888a2463c4 create system user when creating a new hosting package 2015-01-22 00:20:06 +01:00
Jan Dittberner d4f68a155c fix some test issues 2015-01-22 00:19:16 +01:00
Jan Dittberner 680f091cba incomplete create_hosting_package view
- add staff user view create_hosting_package
- add hostingpackages.forms.CreateHostingPackageForm
- add hostingpackages.views.CreateHostingPackage
- add link for staff users on user_dashboard page
- add url pattern
- TODO: implement saving the hosting package, update docs
2015-01-20 00:51:05 +01:00
Jan Dittberner 9890248e80 fix issue with mailbox count calculation
- use 0 if no mailbox option is assigned to the hosting package
2015-01-20 00:49:19 +01:00
Jan Dittberner f211b535cf remove unused LogoutView and corresponding url pattern 2015-01-20 00:47:24 +01:00
Jan Dittberner d78bad06b7 add docstrings to managemails.models 2015-01-19 23:00:01 +01:00
Jan Dittberner 35eceb3307 add task stub for ldaptasks.tasks.set_ldap_user_password 2015-01-19 22:43:29 +01:00
Jan Dittberner 42b5652bdc update changelog 2015-01-19 21:56:48 +01:00
Jan Dittberner 41af99561c adapt documentation to changed module structure 2015-01-19 21:54:13 +01:00
Jan Dittberner 5b41d93898 refactor osusers.tasks into fileservertasks and ldaptasks 2015-01-19 21:44:57 +01:00
Jan Dittberner 12b95881ec add a list of planned features and development ideas
- TODO: setup an issue tracker
2015-01-19 20:43:31 +01:00
Jan Dittberner efd5edd55f Merge branch 'feature/hostingpackages'
* feature/hostingpackages:
  remove newline at EOF
  add changelog entry for hosting package information on user dashboard
  render hosting package table on user dashboard
  implement get_context_data for UserDashboardView
  add CustomerHostingPackage information aggration methods
  fix foreign key for CustomerMailboxOption
  mention hostingpackages app in changelog
  add hostingpackages api doc
  add hostingpackages app to INSTALLED_APPS
  Add new hostingpackages app
2015-01-18 16:26:33 +01:00
Jan Dittberner 7ab58575eb remove newline at EOF 2015-01-18 16:25:41 +01:00
Jan Dittberner 30aa09c0af Merge branch 'master' into feature/hostingpackages
* master:
  load Font Mfizz in base template head
  add userdb template tags
  add Font Mfizz from http://mfizz.com/oss/font-mfizz

merged docs/changelog.rst
2015-01-18 16:24:53 +01:00
Jan Dittberner 8ffa22cc07 add changelog entry for hosting package information on user dashboard 2015-01-18 16:22:00 +01:00
Jan Dittberner d7d41d2fd9 render hosting package table on user dashboard 2015-01-18 16:20:47 +01:00
Jan Dittberner d34f3596ae implement get_context_data for UserDashboardView
- expose user's hosting packages in UserDashboardView.get_context_data
2015-01-18 16:19:28 +01:00
Jan Dittberner 0e32aff544 add CustomerHostingPackage information aggration methods
- add get_disk_space, get_used_mailboxes, get_mailboxes and get_database
  methods for hostingpackages.models.CustomerHostingPackage
2015-01-18 16:14:47 +01:00
Jan Dittberner c72d711d35 load Font Mfizz in base template head 2015-01-18 16:07:06 +01:00
Jan Dittberner 4c8b173e95 add userdb template tags
- add changelog entry
- add generated documentation for userdbs.templatetags.userdb
- add userdb template tags db_type_icon_class and db_type_name
- remove empty userdbs.views
2015-01-18 16:05:29 +01:00
Jan Dittberner 56675f6c4d add Font Mfizz from http://mfizz.com/oss/font-mfizz 2015-01-18 16:01:24 +01:00
Jan Dittberner 95e15806c6 fix foreign key for CustomerMailboxOption 2015-01-18 16:00:18 +01:00
Jan Dittberner 7457754dc6 mention hostingpackages app in changelog 2015-01-18 13:40:16 +01:00
Jan Dittberner 4f2ebbae63 add hostingpackages api doc
- add to docs/code.rst toctree
- add new docs/code/hostingpackages.rst containing the autodoc directives
- document undocumented code in hostingpackages app
- update translation templates
2015-01-18 13:37:21 +01:00
Jan Dittberner 12455e2d99 add hostingpackages app to INSTALLED_APPS 2015-01-18 13:22:31 +01:00
Jan Dittberner 9f63fbbb5d Add new hostingpackages app
- implement models for hosting packages, hosting options and customer
  specific variants
- implement admin interface
- add documentation
2015-01-18 13:22:06 +01:00
Jan Dittberner 3870bcf483 release 0.5.2
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUuvWHAAoJEA15HcjXN8HZ/fgH/00pFSn8YQUccm/Q6oqoemhO
 zDNujonbbLJDjEC+655ZVDhNYaIKZt1b0OLgbScV/HM4Afgqrn+TWiNzyVMeEn7g
 QjbxSHEJn3d4nmNjemIeWYNII8EC0lOQeZB7b62uCk15XSrxVhUwyUwLYxeyJdjD
 S7zK23xWbrA2HDO6bLHjssTDIEEQ876Eq1OujycgCmGFB8yMYqLaqAH9fCHp5zXc
 vCUbt5ezohXBlsaU8vcGEKCcFUZIQ70TKeiiL7ccGF9Cf7hZC63ljZKJmXim1YzR
 SDWQrCKvNqvfXJ9Cl+2/nXL3ctWZ6WnylPwPOUoF7b6yRnvTnINaugX3+ADCgiQ=
 =mvEJ
 -----END PGP SIGNATURE-----

Merge tag '0.5.2'

release 0.5.2

* tag '0.5.2':
  finish release 0.5.2 docs
2015-01-18 00:51:41 +01:00
Jan Dittberner 4fcfdd2670 Merge branch 'release/0.5.2' into production
* release/0.5.2:
  finish release 0.5.2 docs
  define proper allauth production settings
2015-01-18 00:51:18 +01:00
Jan Dittberner 35d84d7f18 finish release 0.5.2 docs 2015-01-18 00:50:43 +01:00
Jan Dittberner 8fd75d5486 define proper allauth production settings 2015-01-18 00:47:59 +01:00
Jan Dittberner 7f382988cf release 0.5.1
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUuvCnAAoJEA15HcjXN8HZzzoIAKda7ElFD218MnsOrOPC5Aej
 6oboQGmqdsb0qvTgJYaxPrYnIKsySJdEak9mDqsX2RMgpLHO3e+pF7lUvI5QI8fL
 1M1IvyMCfl8ci0JLniKp/JMFvieMXUvhHN06sC3lbHOROdUICt5lptGhaBvGs9q9
 chmrC8WzNqLSlEIrEdgH7pelohlbPkXNerpqvCjPhu/LUp4LlYqbF9DjTP6OpWb/
 DFOMZu1oCoEEePNC6aw1FHmZ0LzrcmlUo+hEmrXxK6aZhHloilGmF5aQCx2S793C
 QuUA7OuzhW+JoOCE3QnPfYNYmq1pJbUJJpbVLQfPnJ/gNlFtpEDujcz5uEdviJY=
 =F8il
 -----END PGP SIGNATURE-----

Merge tag '0.5.1'

release 0.5.1

* tag '0.5.1':
  finish release 0.5.1 docs
2015-01-18 00:30:53 +01:00
Jan Dittberner ccfbc79a73 Merge branch 'release/0.5.1' into production
* release/0.5.1:
  finish release 0.5.1 docs
  load jquery and html5shim with same URL schema as the rest of the site
2015-01-18 00:30:39 +01:00
Jan Dittberner e84642263b finish release 0.5.1 docs 2015-01-18 00:30:06 +01:00
Jan Dittberner e121c9bf3d load jquery and html5shim with same URL schema as the rest of the site 2015-01-18 00:28:47 +01:00
Jan Dittberner d8eb7b38db release 0.5.0
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUuub8AAoJEA15HcjXN8HZmAUH/RRZQTAMtU5IS9iSRufEEqL0
 MO4ktcKJ/NdSIfn5UcTcVGkLaEmyVAbeNshDlGiP5PIMlFS9RUHlhBYjwihF4ngo
 LRsh28BmeAQth0K5vFPhvJMy7K8IFX+lzfV8ZZ0fBPWMcvZitmqJk0pnXchFdiNf
 sTU7Pe0SgW5na61uQ4V69tmZ50Plfc3dhHtEDSgXvxNdt/0D8ATg9tUm6CYAO8ZE
 fmJl3yvXADSCOTXh8CpLiHVuvXL0LyssUFapRkKs2aSciZDqeovKgyGsvoDYJTvv
 Des/Tmz16YTaqzIFBT73HEeqA86CbTI5gAeEphscnyQiIv1rwojCL7lxDh9Jpjw=
 =oxXj
 -----END PGP SIGNATURE-----

Merge tag '0.5.0'

release 0.5.0

* tag '0.5.0':
  finalize changelog for release 0.5.0, update docs/conf.py
2015-01-17 23:49:42 +01:00
Jan Dittberner cb58ff6f2c Merge branch 'release/0.5.0' into production
* release/0.5.0: (22 commits)
  finalize changelog for release 0.5.0, update docs/conf.py
  restructure generated code documentation
  remove empty tests module
  document allauth integration
  add socialaccount connections link to user dropdown
  add templates for allauth
  restructure base html to display properly on small devices
  add font-awesome link and put account actions in a dropdown
  add font-awesome css and fonts
  add allauth configuration and message tags
  add allauth settings and URLs
  add django-allauth and its dependencies to requirements/base.txt
  document login/logout/dashboard feature
  add admin site link for staff in base template
  add german translation
  implement login and logout
  add templates for anonymous user dashboard and login
  add dashboard app
  add django-crispy-forms
  add migration for managemails ordering
  ...
2015-01-17 23:49:23 +01:00
Jan Dittberner 21bfe711a1 finalize changelog for release 0.5.0, update docs/conf.py 2015-01-17 23:48:13 +01:00
Jan Dittberner 2408feb4b1 restructure generated code documentation 2015-01-17 23:46:31 +01:00
Jan Dittberner 8ab15e7680 remove empty tests module 2015-01-17 23:27:03 +01:00
Jan Dittberner 54c6e3f714 Merge branch 'feature/allauth-integration'
* feature/allauth-integration:
  document allauth integration
  add socialaccount connections link to user dropdown
  add templates for allauth
  restructure base html to display properly on small devices
  add font-awesome link and put account actions in a dropdown
  add font-awesome css and fonts
  add allauth configuration and message tags
  add allauth settings and URLs
  add django-allauth and its dependencies to requirements/base.txt
2015-01-17 23:24:09 +01:00
Jan Dittberner 8900d6e72d document allauth integration 2015-01-17 23:23:14 +01:00
Jan Dittberner 9d1e315fb4 add socialaccount connections link to user dropdown 2015-01-17 23:09:09 +01:00
Jan Dittberner 92b6e8a8cb add templates for allauth 2015-01-17 23:08:41 +01:00
Jan Dittberner 7d6e0386d8 restructure base html to display properly on small devices 2015-01-17 22:05:47 +01:00
Jan Dittberner d906b9e497 add font-awesome link and put account actions in a dropdown 2015-01-17 21:42:13 +01:00
Jan Dittberner 35016faba0 add font-awesome css and fonts 2015-01-17 21:41:32 +01:00
Jan Dittberner ab313a2a66 add allauth configuration and message tags 2015-01-17 17:50:59 +01:00
Jan Dittberner 286c477efc add allauth settings and URLs 2015-01-17 16:28:19 +01:00
Jan Dittberner 1782c65bac add django-allauth and its dependencies to requirements/base.txt 2015-01-17 16:19:26 +01:00
Jan Dittberner 0a097b09e2 document login/logout/dashboard feature 2015-01-17 16:18:26 +01:00
Jan Dittberner 8cf6aab643 add admin site link for staff in base template 2015-01-17 16:14:55 +01:00
Jan Dittberner 9fa1944c31 add german translation
- add django.po for apps and templates
- add locale directory to LOCALE_PATHS setting
2015-01-17 16:06:25 +01:00
Jan Dittberner 2bc278ae92 implement login and logout
- add LogoutView to dashboard app
- define logout URL pattern
- only use login view from django.contrib.auth.views instead of including all
  auth URLs
- change base template to support login/logout
- add template dashboard/user_dashboard.html
2015-01-17 15:42:47 +01:00
Jan Dittberner 1deed46d34 add templates for anonymous user dashboard and login 2015-01-17 14:05:04 +01:00
Jan Dittberner 8a29e4001c add dashboard app
- add new dashboard app providing dashboards for anonymous and logged in users
- cleanup gnuviechadmin.urls:
  - import dashboard.urls and include dashboard_urls at URL root
  - import authentication urls and include them below /auth
  - remove generated commented code
2015-01-17 14:05:04 +01:00
Jan Dittberner 8884b8b042 add django-crispy-forms
- add django-crispy-forms to requirements
- add crispy_forms app to settings.base
- add CRISPY_TEMPLATE_PACK setting to settings.base
2015-01-17 14:05:04 +01:00
Jan Dittberner 961a2f471b add migration for managemails ordering 2015-01-17 14:05:04 +01:00
Jan Dittberner 19390d369a add admin list filtering and ordering for mail addresses and mailboxes 2015-01-17 12:25:54 +01:00
Jan Dittberner fe40074cde update to Django 1.7.3 2015-01-16 19:39:28 +01:00
Jan Dittberner 9a0ceee062 release 0.4.0
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABCgAGBQJUsom6AAoJEA15HcjXN8HZhKEIAKhhq6Hfbb5j8nnz46jFIJia
 +Klg6pp0iVjz9Lmw9BGKlZ3N+JcfYTOap4lZzhZfW9WCLBoqzzyCBGTLobJNQNuD
 JYndeUAHDTpaQM0o86uEnFQAFRnQ78O7kdAMDFBEkORSibmyIOjeabPJvTvo40+5
 MQKIqyZnXKeObEws2SFxCCUxLG916OqTXXHe6p2RvDXhkHpBIxE3/zQ6jAaVTlzs
 tUZNn6x/Ola6iI17pDpwR70z6T5Xsf5WlPrDlHEp49X0Jjm9YIPH5ob6/jCpNtUe
 C1jdD+P0PntWuw08iD1rp4fqK/Djat9LXMBVEIi1LnOPQ7MrMyYq6KJXqPOoXx0=
 =sTsQ
 -----END PGP SIGNATURE-----

Merge tag '0.4.0'

release 0.4.0

* tag '0.4.0':
  define version number, update changelog
2015-01-11 15:33:35 +01:00
359 changed files with 32483 additions and 2559 deletions

18
.dockerignore Normal file
View file

@ -0,0 +1,18 @@
**/*.pyc
**/.*.swp
**/.coverage
**/__pycache__
.dockerignore
.env
.envrc
.git
.gitignore
.idea
.isort.cfg
.vagrant
Dockerfile
Vagrantfile
docker-compose.yml
docs
media
static

14
.gitignore vendored
View file

@ -44,3 +44,17 @@ htmlcov/
tags
_build/
*.mo
.vagrant/
gnuviechadmin/assets/
coverage-report/
.idea/
.env
.envrc
/docker/django_media
/docker/django_static
!/docker/django_media/.empty
!/docker/django_static/.empty
/media/
/static/

7
.isort.cfg Normal file
View file

@ -0,0 +1,7 @@
[tool.isort]
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0
use_parentheses = True
ensure_newline_before_comments = True
line_length = 88

661
COPYING Normal file
View file

@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.

70
Dockerfile Normal file
View file

@ -0,0 +1,70 @@
ARG DEBIAN_RELEASE=bookworm
FROM debian:$DEBIAN_RELEASE AS builder
ARG GVAAPP=gva
ARG POETRY_VERSION=1.7.1
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
curl \
git \
libpq-dev \
python3-dev \
python3-setuptools \
python3-virtualenv \
python3-wheel
RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=/root/.local POETRY_VERSION=$POETRY_VERSION python3 - \
&& /root/.local/bin/poetry config virtualenvs.in-project true
WORKDIR /srv/$GVAAPP
COPY poetry.lock pyproject.toml /srv/$GVAAPP/
RUN /root/.local/bin/poetry install --only=main --no-root
FROM debian:$DEBIAN_RELEASE
LABEL maintainer="Jan Dittberner <jan@dittberner.info>"
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
dumb-init \
gettext \
postgresql-client \
python3 \
python3-pip \
python3-wheel \
&& apt-get clean \
&& rm -rf /var/cache/apt/archives /var/lib/apt/lists/*
ARG GVAAPP=gva
ARG GVAGID=2000
ARG GVAUID=2000
RUN addgroup --gid $GVAGID $GVAAPP ; \
adduser --home /home/$GVAAPP --shell /bin/bash --uid $GVAUID --gid $GVAGID --disabled-password \
--gecos "User for gnuviechadmin component $GVAAPP" $GVAAPP
COPY --chown=$GVAAPP:$GVAAPP --from=builder /srv/$GVAAPP/.venv /srv/$GVAAPP/.venv
WORKDIR /srv/$GVAAPP
VOLUME /srv/$GVAAPP/media /srv/$GVAAPP/static
VOLUME /srv/$GVAAPP/gnuviechadmin
EXPOSE 8000
COPY ${GVAAPP}.sh entrypoint.sh /srv/
ENTRYPOINT ["dumb-init", "/srv/entrypoint.sh"]

View file

@ -1,22 +0,0 @@
Copyright (c) 2014 Jan Dittberner.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,59 +1,18 @@
=============
gnuviechadmin
=============
-------------
Customer center for gnuviech servers.
This is the GNUViech Admin Customer Center for gnuviech servers.
To use this project follow these steps:
GNUViech Admin is a suite of tools for server management used for hosting
customer management at `Jan Dittberner IT-Consulting & -Solutions
<http://www.gnuviech-server.de>`_.
#. Create your working environment
#. Install Django
#. Create the new project using the django-two-scoops template
#. Install additional dependencies
#. Use the Django admin to create the project
Gnuviechadmin is based on Django_ and Celery_
Working Environment
===================
.. _Django: https://djangoproject.com/
.. _Celery: http://www.celeryproject.com/
You have several options in setting up your working environment. We recommend
using virtualenv to separate the dependencies of your project from your
system's python environment. If on Linux or Mac OS X, you can also use
virtualenvwrapper to help manage multiple virtualenvs across different
projects.
Virtualenv Only
---------------
First, make sure you are using virtualenv (http://www.virtualenv.org). Once
that's installed, create your virtualenv::
$ virtualenv --distribute gnuviechadmin
You will also need to ensure that the virtualenv has the project directory
added to the path. Adding the project directory will allow `django-admin.py` to
be able to change settings using the `--settings` flag.
Virtualenv with virtualenvwrapper
------------------------------------
In Linux and Mac OSX, you can install virtualenvwrapper
(http://virtualenvwrapper.readthedocs.org/en/latest/), which will take care of
managing your virtual environments and adding the project path to the
`site-directory` for you::
$ mkdir gnuviechadmin
$ mkvirtualenv -a gnuviechadmin gnuviechadmin-dev
$ cd gnuviechadmin && add2virtualenv `pwd`
Installation of Dependencies
=============================
Depending on where you are installing dependencies:
In development::
$ pip install -r requirements/local.txt
For production::
$ pip install -r requirements.txt
The project page for gnuviechadmin is at
http://git.dittberner.info/gnuviech/gva. If you find some problem or have some
feature suggestions you can post a new ticket in our issue tracker on the
project page.

113
docker-compose.yml Normal file
View file

@ -0,0 +1,113 @@
---
version: "3"
services:
db:
image: gnuviech/pgsql:buster
ports:
- "15432:5432"
env_file: .env
volumes:
- "pg_data:/var/lib/postgresql/11/main"
mq:
image: gnuviech/mq:buster
env_file: .env
volumes:
- "mq_data:/var/lib/rabbitmq/mnesia"
redis:
image: gnuviech/redis:buster
env_file: .env
volumes:
- "redis_data:/var/lib/redis"
gva:
image: gnuviech/gva:bookworm
build:
context: .
args:
GVAGID: 1000
GVAUID: 1000
ports:
- "8000:8000"
depends_on:
- db
- mq
- redis
env_file: .env
environment:
DJANGO_SETTINGS_MODULE: gnuviechadmin.settings
GVA_DOMAIN_NAME: localhost
GVA_SITE_NAME: localhost
volumes:
- "django_media:/srv/gva/media"
- "django_static:/srv/gva/static"
- "./gnuviechadmin:/srv/gva/gnuviechadmin"
web:
image: gnuviech/gvaweb:buster
build:
context: ../gvaweb
args:
GVAGID: 1000
GVAUID: 1000
depends_on:
- mq
- redis
env_file: ../gvaweb/.env
volumes:
- "../gvaweb/gvaweb:/srv/gvaweb/gvaweb"
ldap:
image: gnuviech/gvaldap:buster
build:
context: ../gvaldap
args:
GVAGID: 1000
GVAUID: 1000
depends_on:
- mq
- redis
env_file: ../gvaldap/.env
volumes:
- "../gvaldap/gvaldap:/srv/gvaldap/gvaldap"
file:
image: gnuviech/gvafile:bookworm
build:
context: ../gvafile
args:
GVAGID: 1000
GVAUID: 1000
depends_on:
- mq
- redis
env_file: ../gvafile/.env
volumes:
- "../gvafile/gvafile:/srv/gvafile/gvafile"
pgsql:
image: gnuviech/gvapgsql:buster
build:
context: ../gvapgsql
args:
GVAGID: 1000
GVAUID: 1000
depends_on:
- mq
- redis
env_file: ../gvapgsql/.env
volumes:
- "../gvapgsql/gvapgsql:/srv/gvapgsql/gvapgsql"
mysql:
image: gnuviech/gvamysql:buster
build:
context: ../gvamysql
args:
GVAGID: 1000
GVAUID: 1000
depends_on:
- mq
- redis
env_file: ../gvamysql/.env
volumes:
- "../gvamysql/gvamysql:/srv/gvamysql/gvamysql"
volumes:
django_media:
django_static:
pg_data:
redis_data:
mq_data:

View file

@ -1,6 +1,168 @@
Changelog
=========
* :release:`0.15.1 <2023-07-23>
* :bug:`-` remove stale disk usage stats older than 30 minutes
* :release:`0.15.0 <2023-07-23>
* :feature:`10` add disk usage details for mail and web
* :release:`0.14.4 <2023-07-22>`
* :bug:`-` add customer to disk space detail view
* :release:`0.14.3 <2023-07-22>`
* :bug:`-` fix missing permission check on disk space detail view
* :release:`0.14.2 <2023-07-22>`
* :bug:`-` fix division by zero for hosting packages without disk space allocation
* :release:`0.14.1 <2023-07-22>`
* :bug:`-` fix squashed migration for disk space statistics
* :release:`0.14.0 <2023-07-22>`
* :feature:`-` add disk space statistics
* :release:`0.13.0 <2023-05-08>`
* :feature:`-` add REST API to retrieve and set user information as admin
* :feature:`-` add support model for offline account reset codes in new help
app
* :support:`-` remove unused PowerDNS support tables from domains app
* :feature:`-` add impersonation support for superusers
* :support:`-` remove django-braces dependency
* :support:`-` remove Twitter support
* :support:`-` update dependencies
* :release:`0.12.1 <2020-04-13>`
* :bug:`7` fix handling of undefined mail domains in customer hosting package
detail template
* :release:`0.12.0 <2020-04-10>`
* :support:`-` add architecture diagramm for documentation
* :support:`-` drop environment specific settings
* :support:`-` update to Python 3
* :support:`-` use Pipenv for dependency management
* :support:`-` switch result backend to Redis
* :support:`-` use separate test vhost for celery queues
* :support:`-` switch licensing to AGPLv3+
* :support:`-` add a Vagrant setup to ease development
* :support:`-` add Docker setup for local development
* :feature:`-` let all celery tasks run asynchronously and move task processing
to signal handlers
* :feature:`-` add unit tests for all the code
* :feature:`-` add proper configuration for coverage, flake8 and pep8
* :feature:`-` update to Django 2.2.12
* :support:`-` use gvacommon from separate repository
* :support:`-` update documentation
* :release:`0.11.6 <2020-02-14>`
* :support:`-` Update dependencies to versions that work with Debian Stretch
* :release:`0.11.5 <2018-12-26>`
* :support:`-` Remove Xing support from settings and templates
* :release:`0.11.4 <2016-12-31>`
* :bug:`-` fix wrong tag in password reset done template
* :release:`0.11.3 <2015-02-21>`
* :bug:`-` fix handling of OpenSSH formatted keys with whitespace in comments
* :bug:`-` the ssh key list does not show SSH keys of other users anymore
* :release:`0.11.2 <2015-02-06>`
* :bug:`-` fix wrong variable name in
managemails.models.MailAddress.set_forward_addresses and typo in
managemails.forms.EditMailAddressForm
* :release:`0.11.1 <2015-02-01>`
* :bug:`-` fix translation of contact form by using ugettext_lazy and adding
contact_form to INSTALLED_APPS
* :release:`0.11.0 <2015-02-01>`
* :feature:`-` add icons to top level navigation
* :feature:`-` add contact form
* :feature:`-` add imprint as flatpage
* :support:`-` mark active menu item as active via context_processor and
corresponding template markup
* :feature:`-` add links to webmail, phpmyadmin and phppgadmin
* :release:`0.10.0 <2015-02-01>`
* :support:`-` move taskresults tests to tasksresults.tests and fix them
* :support:`-` cache result of get_hosting_package method of
gvawebcore.views.HostingPackageAndCustomerMixin to improve page loading
performance
* :feature:`-` add ability to add, list and delete SSH public keys assigned to
a hosting package's operating system user and change their comments
* :feature:`-` add ability to add SSH public keys for operating system users
* :support:`-` make tests in osusers.tests work again
* :support:`-` minor HTML improvements
* :support:`-` add API for gvafile task set_file_ssh_authorized_keys (requires
gvafile >= 0.5.0 on the fileserver side)
* :support:`-` update to Django 1.7.4
* :release:`0.9.0 <2015-01-27>`
* :feature:`-` setup nginx virtual host and PHP configuration for websites
(requires gvaweb >= 0.1.0 on web server)
* :support:`-` implement domain name validation
* :feature:`-` implement deletion of websites
* :feature:`-` implement setup of websites
* :support:`-` add webtasks interface
* :support:`-` update to new fileservertasks interface (requires gvafile >=
0.4.0 on the fileserver)
* :release:`0.8.0 <2015-01-26>`
* :feature:`-` implement deletion of user database and database users
* :feature:`-` implement password changes for database users
* :feature:`-` implement setup of user databases
* :support:`-` performance improvement for hosting package detail view
* :support:`-` move HostingPackageAndCustomerMixin from managemails.views to
gvawebcore.views
* :release:`0.7.0 <2015-01-25>`
* :feature:`-` implement mail address target editing
* :feature:`-` implement mail address deletion
* :feature:`-` implement adding mail address to mail domains
* :feature:`-` implement adding options to hosting packages
* :bug:`- major` fix disk space calculation in
hostingpackages.models.CustomerHostingPackage
* :bug:`- major` fix unique constraints on
hostingpackages.models.CustomerDiskSpaceOption and
hostingpackages.models.CustomerDatabaseOption
* :feature:`-` implement password change functionality for mailboxes
* :feature:`-` implement creation of new mailboxes for hosting packages
* :support:`-` move common form code to new module gvawebcore.forms
* :feature:`-` make it possible to assign domains to a customer
* :feature:`-` add hosting packages list for staff users
* :feature:`-` allow creation of new hosting packages for staff users without
the need to navigate to a customer dashboard first
* :release:`0.6.0 <2015-01-24>`
* :feature:`-` add frontend functionality to set an os users' sftp password
(needs gvaldap >= 0.4.0 on the LDAP side)
* :support:`-` remove unused dashboard.views.LogoutView and the corresponding
URL in dashboard.urls
* :feature:`-` add new task stub to set an ldap user's password
* :support:`-` refactor osusers.tasks, split into fileservertasks.tasks and
ldaptasks.tasks
* :feature:`-` show hosting package information on user dashboard
* :feature:`-` implement new hostingpackages app to provide hosting package
templates, hosting options and customer hosting packages as well as customer
specific hosting package options
* :feature:`-` add template tags for database icons and human readable names in
:py:mod:`userdbs.templatetags.userdb`
* :release:`0.5.2 <2015-01-18>`
* :bug:`-` define proper allauth production settings with https and mandatory
email verification
* :release:`0.5.1 <2015-01-18>`
* :bug:`-` load jquery and html5 with same URL schema as the rest of the site
* :release:`0.5.0 <2015-01-17>`
* :feature:`-` add authentication via social media accounts from Google,
LinkedIn, Twitter and Xing
* :feature:`-` add customer login/logout and dashboard templates
* :feature:`-` add admin list filtering and ordering for mail addresses and
mailboxes
* :release:`0.4.0 <2015-01-11>`
* :feature:`-` add mysqltasks and pgsqltasks
* :feature:`-` add :py:mod:`userdbs` app to allow management of user databases

View file

@ -9,227 +9,39 @@ administrators and customers.
.. _Django: https://www.djangoproject.com/
Common code
===========
The project module :py:mod:`gnuviechadmin`
==========================================
.. toctree::
.. automodule:: gnuviechadmin
code/gvacommon
code/gvawebcore
:py:mod:`celery <gnuviechadmin.celery>`
---------------------------------------
Celery task stubs
=================
.. automodule:: gnuviechadmin.celery
:members:
.. toctree::
code/fileservertasks
code/ldaptasks
code/mysqltasks
code/pgsqltasks
code/webtasks
:py:mod:`urls <gnuviechadmin.urls>`
-----------------------------------
.. automodule:: gnuviechadmin.urls
Django app code
===============
.. toctree::
:py:mod:`wsgi <gnuviechadmin.wsgi>`
-----------------------------------
.. automodule:: gnuviechadmin.wsgi
:members:
:py:mod:`settings <gnuviechadmin.settings>`
-------------------------------------------
.. automodule:: gnuviechadmin.settings
:py:mod:`base <gnuviechadmin.settings.base>`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: gnuviechadmin.settings.base
:members:
:py:mod:`local <gnuviechadmin.settings.local>`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: gnuviechadmin.settings.local
:py:mod:`production <gnuviechadmin.settings.production>`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: gnuviechadmin.settings.production
:py:mod:`test <gnuviechadmin.settings.test>`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: gnuviechadmin.settings.test
:py:mod:`gvacommon`
===================
This module is imported from a separate git project via git subtree and
provides some functionality that is common to all gnuviechadmin subprojects.
.. automodule:: gvacommon
:py:mod:`celeryrouters <gvacommon.celeryrouters>`
-------------------------------------------------
.. automodule:: gvacommon.celeryrouters
:members:
:undoc-members:
:py:mod:`managemails` app
=========================
.. automodule:: managemails
:py:mod:`admin <managemails.admin>`
-----------------------------------
.. automodule:: managemails.admin
:members:
:py:mod:`models <managemails.models>`
-------------------------------------
.. automodule:: managemails.models
:members:
:py:mod:`mysqltasks` app
========================
.. automodule:: mysqltasks
:py:mod:`tasks <mysqltasks.tasks>`
----------------------------------
.. automodule:: mysqltasks.tasks
:members:
.. autotask:: mysqltasks.tasks.create_mysql_database
.. autotask:: mysqltasks.tasks.create_mysql_user
.. autotask:: mysqltasks.tasks.delete_mysql_database
.. autotask:: mysqltasks.tasks.delete_mysql_user
.. autotask:: mysqltasks.tasks.set_mysql_userpassword
:py:mod:`osusers` app
=====================
.. automodule:: osusers
:py:mod:`admin <osusers.admin>`
-------------------------------
.. automodule:: osusers.admin
:members:
:py:mod:`apps <osusers.apps>`
-----------------------------
.. automodule:: osusers.apps
:members:
:py:mod:`models <osusers.models>`
---------------------------------
.. automodule:: osusers.models
:members:
:py:mod:`tasks <osusers.tasks>`
-------------------------------
.. automodule:: osusers.tasks
.. autotask:: osusers.tasks.add_ldap_user_to_group
.. autotask:: osusers.tasks.create_file_mailbox
.. autotask:: osusers.tasks.create_ldap_group
.. autotask:: osusers.tasks.create_ldap_user
.. autotask:: osusers.tasks.delete_file_mail_userdir
.. autotask:: osusers.tasks.delete_file_mailbox
.. autotask:: osusers.tasks.delete_file_sftp_userdir
.. autotask:: osusers.tasks.delete_ldap_group
.. autotask:: osusers.tasks.delete_ldap_group_if_empty
.. autotask:: osusers.tasks.delete_ldap_user
.. autotask:: osusers.tasks.remove_ldap_user_from_group
.. autotask:: osusers.tasks.setup_file_mail_userdir
.. autotask:: osusers.tasks.setup_file_sftp_userdir
:py:mod:`pgsqltasks` app
========================
.. automodule:: pgsqltasks
:members:
:py:mod:`tasks <pgsqltasks.tasks>`
----------------------------------
.. automodule:: pgsqltasks.tasks
.. autotask:: pgsqltasks.tasks.create_pgsql_database
.. autotask:: pgsqltasks.tasks.create_pgsql_user
.. autotask:: pgsqltasks.tasks.delete_pgsql_database
.. autotask:: pgsqltasks.tasks.delete_pgsql_user
.. autotask:: pgsqltasks.tasks.set_pgsql_userpassword
:py:mod:`taskresults` app
=========================
.. automodule:: taskresults
:py:mod:`admin <taskresults.admin>`
-----------------------------------
.. automodule:: taskresults.admin
:py:mod:`management.commands <taskresults.management.commands>`
---------------------------------------------------------------
.. automodule:: taskresults.management.commands
:py:mod:`fetch_taskresults <taskresult.management.commands.fetch_taskresults>`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: taskresults.management.commands.fetch_taskresults
:py:mod:`models <taskresults.models>`
-------------------------------------
.. automodule:: taskresults.models
:py:mod:`userdbs` app
=====================
.. automodule:: userdbs
:py:mod:`admin <userdbs.admin>`
-------------------------------
.. automodule:: userdbs.admin
:members:
:py:mod:`models <userdbs.models>`
---------------------------------
.. automodule:: userdbs.models
:members:
code/gnuviechadmin
code/contact_form
code/dashboard
code/domains
code/hostingpackages
code/managemails
code/osusers
code/taskresults
code/userdbs
code/websites

View file

@ -0,0 +1,24 @@
:py:mod:`contact_form` app
==========================
.. automodule:: contact_form
:py:mod:`forms <contact_form.forms>`
------------------------------------
.. automodule:: contact_form.forms
:members:
:py:mod:`urls <contact_form.urls>`
----------------------------------
.. automodule:: contact_form.urls
:py:mod:`views <contact_form.views>`
------------------------------------
.. automodule:: contact_form.views
:members:

22
docs/code/dashboard.rst Normal file
View file

@ -0,0 +1,22 @@
:py:mod:`dashboard` app
=======================
.. automodule:: dashboard
:py:mod:`models <dashboard.models>`
-----------------------------------
.. automodule:: dashboard.models
:py:mod:`urls <dashboard.urls>`
-------------------------------
.. automodule:: dashboard.urls
:py:mod:`views <dashboard.views>`
---------------------------------
.. automodule:: dashboard.views

46
docs/code/domains.rst Normal file
View file

@ -0,0 +1,46 @@
:py:mod:`domains` app
=====================
.. automodule:: domains
:py:mod:`admin <domains.admin>`
-------------------------------
.. automodule:: domains.admin
:members:
:py:mod:`apps <domains.apps>`
-----------------------------
.. automodule:: domains.apps
:members:
:py:mod:`forms <domains.forms>`
-------------------------------
.. automodule:: domains.forms
:members:
:py:mod:`models <domains.models>`
---------------------------------
.. automodule:: domains.models
:members:
:py:mod:`urls <domains.urls>`
-----------------------------
.. automodule:: domains.urls
:members:
:py:mod:`views <domains.views>`
-------------------------------
.. automodule:: domains.views
:members:

View file

@ -0,0 +1,12 @@
:py:mod:`fileservertasks` app
=============================
.. automodule:: fileservertasks
:py:mod:`tasks <fileservertasks.tasks>`
---------------------------------------
.. automodule:: fileservertasks.tasks
:members:
:undoc-members:

View file

@ -0,0 +1,38 @@
The project module :py:mod:`gnuviechadmin`
==========================================
.. automodule:: gnuviechadmin
:py:mod:`celery <gnuviechadmin.celery>`
---------------------------------------
.. automodule:: gnuviechadmin.celery
:members:
:py:mod:`context_processors <gnuviechadmin.context_processors>`
---------------------------------------------------------------
.. automodule:: gnuviechadmin.context_processors
:members:
:py:mod:`urls <gnuviechadmin.urls>`
-----------------------------------
.. automodule:: gnuviechadmin.urls
:py:mod:`wsgi <gnuviechadmin.wsgi>`
-----------------------------------
.. automodule:: gnuviechadmin.wsgi
:members:
:py:mod:`settings <gnuviechadmin.settings>`
-------------------------------------------
.. automodule:: gnuviechadmin.settings
:members:

23
docs/code/gvacommon.rst Normal file
View file

@ -0,0 +1,23 @@
:py:mod:`gvacommon`
===================
This module is imported from a separate git project via git subtree and
provides some functionality that is common to all gnuviechadmin subprojects.
.. automodule:: gvacommon
:py:mod:`celeryrouters <gvacommon.celeryrouters>`
-------------------------------------------------
.. automodule:: gvacommon.celeryrouters
:members:
:undoc-members:
:py:mod:`viewmixins <gvacommon.viewmixins>`
-------------------------------------------
.. automodule:: gvacommon.viewmixins
:members:
:undoc-members:

18
docs/code/gvawebcore.rst Normal file
View file

@ -0,0 +1,18 @@
:py:mod:`gvawebcore`
====================
.. automodule:: gvawebcore
:py:mod:`forms <gvawebcore.forms>`
----------------------------------
.. automodule:: gvawebcore.forms
:members:
:py:mod:`views <gvawebcore.views>`
----------------------------------
.. automodule:: gvawebcore.views
:members:

View file

@ -0,0 +1,38 @@
:py:mod:`hostingpackages` app
=============================
.. automodule:: hostingpackages
:py:mod:`admin <hostingpackages.admin>`
---------------------------------------
.. automodule:: hostingpackages.admin
:members:
:py:mod:`apps <hostingpackages.apps>`
-------------------------------------
.. automodule:: hostingpackages.apps
:members:
:py:mod:`models <hostingpackages.models>`
-----------------------------------------
.. automodule:: hostingpackages.models
:members:
:py:mod:`views <hostingpackages.views>`
---------------------------------------
.. automodule:: hostingpackages.views
:members:
:py:mod:`urls <hostingpackages.urls>`
-------------------------------------
.. automodule:: hostingpackages.urls
:members:

12
docs/code/ldaptasks.rst Normal file
View file

@ -0,0 +1,12 @@
:py:mod:`ldaptasks` app
=======================
.. automodule:: ldaptasks
:py:mod:`tasks <ldaptasks.tasks>`
---------------------------------
.. automodule:: ldaptasks.tasks
:members:
:undoc-members:

46
docs/code/managemails.rst Normal file
View file

@ -0,0 +1,46 @@
:py:mod:`managemails` app
=========================
.. automodule:: managemails
:py:mod:`admin <managemails.admin>`
-----------------------------------
.. automodule:: managemails.admin
:members:
:py:mod:`apps <managemails.apps>`
---------------------------------
.. automodule:: managemails.apps
:members:
:py:mod:`forms <managemails.forms>`
-----------------------------------
.. automodule:: managemails.forms
:members:
:py:mod:`models <managemails.models>`
-------------------------------------
.. automodule:: managemails.models
:members:
:py:mod:`urls <managemails.urls>`
---------------------------------
.. automodule:: managemails.urls
:members:
:py:mod:`views <managemails.views>`
-----------------------------------
.. automodule:: managemails.views
:members:

12
docs/code/mysqltasks.rst Normal file
View file

@ -0,0 +1,12 @@
:py:mod:`mysqltasks` app
========================
.. automodule:: mysqltasks
:py:mod:`tasks <mysqltasks.tasks>`
----------------------------------
.. automodule:: mysqltasks.tasks
:members:
:undoc-members:

51
docs/code/osusers.rst Normal file
View file

@ -0,0 +1,51 @@
:py:mod:`osusers` app
=====================
.. automodule:: osusers
:py:mod:`admin <osusers.admin>`
-------------------------------
.. automodule:: osusers.admin
:members:
:py:mod:`apps <osusers.apps>`
-----------------------------
.. automodule:: osusers.apps
:members:
:py:mod:`forms <osusers.forms>`
-------------------------------
.. automodule:: osusers.forms
:members:
:py:mod:`models <osusers.models>`
---------------------------------
.. automodule:: osusers.models
:members:
:py:mod:`signals <osusers.signals>`
-----------------------------------
.. automodule:: osusers.signals
:members:
:py:mod:`urls <osusers.urls>`
-----------------------------
.. automodule:: osusers.urls
:py:mod:`views <osusers.views>`
-------------------------------
.. automodule:: osusers.views
:members:

13
docs/code/pgsqltasks.rst Normal file
View file

@ -0,0 +1,13 @@
:py:mod:`pgsqltasks` app
========================
.. automodule:: pgsqltasks
:members:
:py:mod:`tasks <pgsqltasks.tasks>`
----------------------------------
.. automodule:: pgsqltasks.tasks
:members:
:undoc-members:

24
docs/code/taskresults.rst Normal file
View file

@ -0,0 +1,24 @@
:py:mod:`taskresults` app
=========================
.. automodule:: taskresults
:py:mod:`admin <taskresults.admin>`
-----------------------------------
.. automodule:: taskresults.admin
:py:mod:`management.commands <taskresults.management.commands>`
---------------------------------------------------------------
.. automodule:: taskresults.management.commands
:py:mod:`fetch_taskresults <taskresult.management.commands.fetch_taskresults>`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: taskresults.management.commands.fetch_taskresults
:py:mod:`models <taskresults.models>`
-------------------------------------
.. automodule:: taskresults.models

63
docs/code/userdbs.rst Normal file
View file

@ -0,0 +1,63 @@
:py:mod:`userdbs` app
=====================
.. automodule:: userdbs
:py:mod:`admin <userdbs.admin>`
-------------------------------
.. automodule:: userdbs.admin
:members:
:py:mod:`apps <userdbs.apps>`
-----------------------------
.. automodule:: userdbs.apps
:py:mod:`forms <userdbs.forms>`
-------------------------------
.. automodule:: userdbs.forms
:members:
:py:mod:`models <userdbs.models>`
---------------------------------
.. automodule:: userdbs.models
:members:
:py:mod:`signals <userdbs.signals>`
-----------------------------------
.. automodule:: userdbs.signals
:members:
:py:mod:`templatetags <userdbs.templatetags>`
---------------------------------------------
.. automodule:: userdbs.templatetags
:py:mod:`userdb <userdbs.templatetags.userdb>`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. automodule:: userdbs.templatetags.userdb
:members:
:py:mod:`urls <userdbs.urls>`
-----------------------------
.. automodule:: userdbs.urls
:members:
:py:mod:`views <userdbs.views>`
-------------------------------
.. automodule:: userdbs.views
:members:

46
docs/code/websites.rst Normal file
View file

@ -0,0 +1,46 @@
:py:mod:`websites` app
======================
.. automodule:: websites
:py:mod:`admin <websites.admin>`
--------------------------------
.. automodule:: websites.admin
:members:
:py:mod:`apps <websites.apps>`
------------------------------
.. automodule:: websites.apps
:members:
:py:mod:`forms <websites.forms>`
--------------------------------
.. automodule:: websites.forms
:members:
:py:mod:`models <websites.models>`
----------------------------------
.. automodule:: websites.models
:members:
:py:mod:`urls <websites.urls>`
------------------------------
.. automodule:: websites.urls
:members:
:py:mod:`views <websites.views>`
--------------------------------
.. automodule:: websites.views
:members:

12
docs/code/webtasks.rst Normal file
View file

@ -0,0 +1,12 @@
:py:mod:`webtasks`
==================
.. automodule:: webtasks
:py:mod:`tasks <webtasks.tasks>`
--------------------------------
.. automodule:: webtasks.tasks
:members:
:undoc-members:

View file

@ -20,163 +20,173 @@ import django
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath(os.path.join('..', 'gnuviechadmin')))
sys.path.insert(0, os.path.abspath(os.path.join("..", "gnuviechadmin")))
os.environ['GVA_SITE_ADMINMAIL'] = 'admin@gva.example.org'
os.environ["DJANGO_SETTINGS_MODULE"] = "gnuviechadmin.settings"
os.environ["GVA_SITE_ADMINMAIL"] = "admin@gva.example.org"
django.setup()
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['releases', 'sphinx.ext.autodoc', 'celery.contrib.sphinx']
extensions = [
"releases",
"sphinx.ext.autodoc",
"celery.contrib.sphinx",
"sphinxcontrib.blockdiag",
]
# configuration for releases extension
releases_issue_uri = 'https://dev.gnuviech-server.de/gva/ticket/%s'
releases_release_uri = 'https://dev.gnuviech-server.de/gva/milestone/%s'
releases_issue_uri = "https://git.dittberner.info/gnuviech/gva/issues/%s"
releases_release_uri = "https://git.dittberner.info/gnuviech/gva/src/tag/%s"
# configuration for blockdiag extension
blockdiag_fontpath = "/usr/share/fonts/truetype/dejavu/"
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]
# The suffix of source filenames.
source_suffix = '.rst'
source_suffix = ".rst"
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
master_doc = "index"
# General information about the project.
project = u'gnuviechadmin'
copyright = u'2014, 2015 Jan Dittberner'
project = "gnuviechadmin"
copyright = "2014-2023, Jan Dittberner"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.4'
# The full version, including alpha/beta/rc tags.
release = '0.4.0'
from gnuviechadmin import __version__ as release
# The short X.Y version.
version = ".".join(release.split(".")[:2])
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
exclude_patterns = ["_build"]
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
html_theme = "alabaster"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'gnuviechadmindoc'
htmlhelp_basename = "gnuviechadmindoc"
# -- Options for LaTeX output --------------------------------------------------
@ -184,10 +194,8 @@ htmlhelp_basename = 'gnuviechadmindoc'
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
@ -195,29 +203,34 @@ latex_elements = {
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'gnuviechadmin.tex', u'gnuviechadmin Documentation',
u'Jan Dittberner', 'manual'),
(
"index",
"gnuviechadmin.tex",
"gnuviechadmin Documentation",
"Jan Dittberner",
"manual",
),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
@ -225,12 +238,11 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'gnuviechadmin', u'gnuviechadmin Documentation',
[u'Jan Dittberner'], 1)
("index", "gnuviechadmin", "gnuviechadmin Documentation", ["Jan Dittberner"], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
@ -239,16 +251,22 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'gnuviechadmin', u'gnuviechadmin Documentation',
u'Jan Dittberner', 'gnuviechadmin', 'Customer center for gnuviech servers.',
'Miscellaneous'),
(
"index",
"gnuviechadmin",
"gnuviechadmin Documentation",
"Jan Dittberner",
"gnuviechadmin",
"Customer center for gnuviech servers.",
"Miscellaneous",
),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# texinfo_show_urls = 'footnote'

View file

@ -1,4 +1,11 @@
Deploy
========
======
This is where you describe how the project is deployed in production.
The production deployment for gnuviechadmin is performed using saltstack and
consists of the following steps:
* installation of native dependencies
* setup of a virtualenv
* installation of gnuviechadmin production dependencies inside the virtualenv
* setup of uwsgi application for the web interface
* setup of nginx with certificates and UWSGI support

View file

@ -0,0 +1 @@
<mxfile host="app.diagrams.net" modified="2020-04-05T12:20:31.231Z" agent="5.0 (X11)" etag="7DgPwm3LEHCQ2g0Mvyzq" version="12.9.7" type="device"><diagram id="NsmcGlYAI3yPeXriofTy" name="Page-1">7Vpbb6M6EP41eQziDnls2mbPSl2pPX3Y06fIAYd4FzA1Jk32159xMAnEtElbcqu2qlo8tmE833zj8aVnXSeLbwxlsx80xHHP1MNFz7rpmaZhm2ZP/OrhspT4ulUKIkZC2WgjeCR/sBTqUlqQEOeNhpzSmJOsKQxomuKAN2SIMfrSbDalcfOrGYqwIngMUKxKf5KQz+QoTG8j/weTaFZ92XAHZU2CqsZyJPkMhfSlJrJue9Y1o5SXT8niGsfCeJVdyn6jV2rXijGc8n06PD48osH3+6uh9fw8mt4/3ekPP/vyLXMUF3LA/+KQ5FJjvqzMgPKstO6ULDC8cDjjSQxFAx4zSlK+MrMz7Dk3IEExiVIQBKAaZiAgycrMwylNucTYMDfyG5JEoHhMJvA3yQOE4f81CmZ4vFJnfM9oWARcy+cR9JI6Y8bx4lVjGGsTg29immDOltBEdhh4tua5ZS/pmbZjaE4pedkgPXA00y6lsxrOvgQVSfeK1l/YICDGUoLwDkBMX7E9DsEjZTGlqbAjo0UaChxudCj9KpKsaoBYABLK+IxGNEXxHaWZxOkX5nwprY8KTpsoTkkcX9OYstVHrRBhfypelXNGf+NajRv4eDIVNZVDCx0CmpBAPpcjEGq/jQ6MkhYswG+ZQ1IesQjzXX6sos1wjDiZN/XoHjOFRNEcZVH+HCtY0oLHJAVzVtFK2CtE+WwNpnBrAvHnDk1wfE9zwgkVXJpQzmlSa3AlScYFwCrlatACUJn4frKIRJDW0EtuaRnNecTwGLQckzTnKA2w6gbmrWcNfZBDz5DAu6s66YgdUNFYx3pJRMfUPJWIrq6y0LUOhaj3l4U1c1iXwEKrjYXJ8rxZuNJvHE7WFBybpyGhfn4ktBVAzxjIswmnpm0305oKs5PFUuf9sfQDkVMNv+cZS51LiKVOWywFe2IFyp38emvl0M69Jj7SPxRCtlJ/m5oB4YwsNKH5OMdsvurZAclc3WuSTOWYZ6gcG3iH4ph9FI6dJ6PcS2CU28aoOETZZTIqJAzaULbslFb2VhLSQivXUWnl+9XCvXtiuX8XAjVzeJdANa+Nai94cplMA8U75ZivD3ZOXa7WwrLBoba8DHXy+vRMBcZgy/9EfxiKLD7J160KN4tGaVkv3WNGYGjC4l0TyN+TQPYpCWSo6V+O07BnujHoPJwweIp4GWUSJCqOkHvgBeEloJ4ji0+1qg2eotCAs+yl601H0HTrQnzB0E/qDGo4zQrRbdsZGM6LmKtHBwdxhhquVhNWy/gIrOc53e7tIW9GfLCR6/uNoC8V2NuD5LvvxUlPrQmdTnNQbNvF1ip83Ot8xekqhwvJvPI4mNYrKXykVqH4YDW3VudQO+fxnalBLCqGKPgdrZy55iHT1U9PHm5dVSmE3pZPVOdfM87FeeaVsKM5CsJU10hA0ykBmjANvEuMD3EY7kjIc/Ff5BIp5n2RSUDZMQQK36V0fAfSvu71DdPXsjTqIHHY3qZfl2uZg1EdX9UTh7Ww+9hkdZ85dEhfS9+Tv/4nA/wWPdeH703SW6an6Y7pWobj+QPb21ozlcOR7+ie0cbgyGmC4dq1PGGdGrTnCVA44Exv7OsI7iln+vVFhWMhBA5ZR0jTDfciUHJOipJxFJROYVfvpHZVT5e+il2tk9pVnaO/il3NU9q10rJ+dQtNJoT/eFAMvjOb3ZkPK1tYrRtdW6soXR/ejsyWrS30p2BYey5wgccRTiGki7XW6h4ZZrdzXF4n28D6qbzVGWxtKrcciBptpzXuwW4qfCCE11eYnWwwN9avHbLHHBwp6f1cVBoo7GlZYF6FCRGLra+5xjR3rjFxngP+BMX9FzwR4W7kAHdGRY5ZH4VhP4uLvB8wjDiGMtiqw+Wm3WStr5LWb1lr+odaalpquFU8oHVbX1x5rd8AscyR+OxrN0C2L4xUzVvj7aFvumxf112V5Xhbfa0thLdcl7E14UJ5N/F9y1Esr+VAo8VTvPd7ChQ317XLdfHm0rt1+z8=</diagram></mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 59 KiB

8
docs/ideas.rst Normal file
View file

@ -0,0 +1,8 @@
Development ideas and planned features
======================================
* add pure redirect websites
* add management for rewrite rules
* add accounts without SFTP (for pure mail hosting)
* allow generation of Key and CSR, add upload of certificates for HTTPS sites
* add XMPP management

View file

@ -3,23 +3,40 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
=========================================
Welcome to gnuviechadmin's documentation!
=========================================
Contents:
.. include:: ../README.rst
Contents
--------
.. toctree::
:maxdepth: 2
:maxdepth: 3
install
deploy
tests
code
ideas
task_flows
changelog
License
-------
gnuviechadmin is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
.. include:: ../COPYING
:literal:
Indices and tables
==================
------------------
* :ref:`genindex`
* :ref:`modindex`

View file

@ -1,4 +1,22 @@
Install
=========
.. index:: installation
This is where you write how to get a new laptop to run this project.
=======
Install
=======
Working Environment
===================
To get a running work environment use `pipenv`_.
.. _pipenv: https://pipenv.kennethreitz.org/en/latest/
To get started install `pip` and `pipenv` and use `pipenv install --dev`:
.. code-block:: sh
$ apt install python3-pip
$ python3 -m pip install --user -U pipenv
$ pipenv install --dev
$ cd gnuviechadmin && add2virtualenv `pwd`

View file

@ -0,0 +1,198 @@
# Regular queries
gpgsql-basic-query=SELECT content, ttl, prio, type, domain_id, disabled::int, name, auth::int \
FROM domains_dnsrecord \
WHERE disabled=false AND type='%s' AND name=E'%s'
gpgsql-id-query=SELECT content, ttl, prio, type, domain_id, disabled::int, name, auth::int \
FROM domains_dnsrecord \
WHERE disabled=false AND type='%s' AND name=E'%s' AND domain_id=%d
gpgsql-any-query=SELECT content, ttl, prio, type, domain_id, disabled::int, name, auth::int \
FROM domains_dnsrecord \
WHERE disabled=false AND name=E'%s'
gpgsql-any-id-query=SELECT content, ttl, prio, type, domain_id, disabled::int, name, auth::int \
FROM domains_dnsrecord \
WHERE disabled=false AND name=E'%s' AND domain_id=%d
gpgsql-list-query=SELECT content, ttl, prio, type, domain_id, disabled::int, name, auth::int \
FROM domains_dnsrecord \
WHERE (disabled=false OR %d::bool) AND domain_id='%d' \
ORDER BY name, type
# Master/slave queries
gpgsql-master-zone-query=SELECT master \
FROM domains_dnsdomain \
WHERE domain=E'%s' AND type='SLAVE'
gpgsql-info-zone-query=SELECT id, domain, master, last_check, notified_serial, type \
FROM domains_dnsdomain \
WHERE domain=E'%s'
gpgsql-info-all-slaves-query=SELECT id, domain, master, last_check, type \
FROM domains_dnsdomain \
WHERE type='SLAVE'
gpgsql-supermaster-query=SELECT customer \
FROM domains_dnssupermaster \
WHERE ip='%s' AND nameserver=E'%s'
gpgsql-insert-slave-query=INSERT INTO domains_dnsdomain \
(type, domain, master, account) \
VALUES ('SLAVE', E'%s', E'%s', E'%s')
gpgsql-insert-record-query=INSERT INTO domains_dnsrecord \
(content, ttl, prio, type, domain_id, disabled, name, auth) \
VALUES (E'%s', %d, %d, '%s', %d, %d::bool, E'%s', '%d')
gpgsql-update-serial-query=UPDATE domains_dnsdomain \
SET notified_serial=%d \
WHERE id=%d
gpgsql-update-lastcheck-query=UPDATE domains_dnsdomain \
SET last_check=%d \
WHERE id=%d
gpgsql-info-all-master-query=SELECT id, domain, master, last_check, notified_serial, type \
FROM domains_dnsdomain \
WHERE type='MASTER'
gpgsql-delete-zone-query=DELETE FROM domains_dnsrecord \
WHERE domain_id=%d
# Comment queries
gpgsql-list-comments-query=SELECT domain_id, name, type, modified_at, customer, comment \
FROM domains_dnscomment \
WHERE domain_id=%d
gpgsql-insert-comment-query=INSERT INTO domains_dnscomment \
(domain_id, name, type, modified_at, customer, comment) \
VALUES (%d, E'%s', E'%s', %d, E'%s', E'%s')
gpgsql-delete-comment-rrset-query=DELETE FROM domains_dnscomment \
WHERE domain_id=%d AND name=E'%s' AND type=E'%s'
gpgsql-delete-comments-query=DELETE FROM domains_dnscomment \
WHERE domain_id=%d
# Crypto key queries
gpgsql-activate-domain-key-query=UPDATE domains_dnscryptokey \
SET active=true \
WHERE domain_id=( \
SELECT id \
FROM domains_dnsdomain \
WHERE domain=E'%s' \
) AND domains_dnscryptokey.id=%d
gpgsql-add-domain-key-query=INSERT INTO domains_dnscryptokey \
(domain_id, flags, active, content) \
SELECT id, %d, (%d = 1), '%s' FROM domains_dnsdomain \
WHERE domain=E'%s'
gpgsql-clear-domain-all-keys-query=DELETE FROM domains_dnscryptokey \
WHERE domain_id=( \
SELECT id FROM domains_dnsdomain \
WHERE domain=E'%s' \
)
gpgsql-deactivate-domain-key-query=UPDATE domains_dnscryptokey \
SET active=false \
WHERE domain_id=( \
SELECT id FROM domains_dnsdomain \
WHERE domain=E'%s' \
) AND domains_dnscryptokey.id=%d
gpgsql-list-domain-keys-query=SELECT domains_dnscryptokey.id, flags, CASE WHEN active THEN 1 ELSE 0 END AS active, content \
FROM domains_dnsdomain, domains_cryptokey \
WHERE domains_dnscryptokey.domain_id=domains_dnsdomain.id AND domain=E'%s'
gpgsql-remove-domain-key-query=DELETE FROM domains_dnscryptokey \
WHERE domain_id=( \
SELECT id FROM domains_dnsdomain \
WHERE domain=E'%s' \
) AND domains_dnscryptokey.id=%d
# TSIG key queries
gpgsql-delete-tsig-key-query=DELETE FROM domains_dnstsigkey \
WHERE name='%s'
gpgsql-get-tsig-key-query=SELECT algorithm, secret \
FROM domains_dnstsigkey \
WHERE name=E'%s'
gpgsql-get-tsig-keys-query=SELECT name, algorithm, secret \
FROM domains_dnstsigkey
gpgsql-set-tsig-key-query=INSERT INTO domains_dnstsigkey \
(name, algorithm, secret) \
VALUES ('%s', '%s', '%s')
# Metadata queries
gpgsql-clear-domain-all-metadata-query=DELETE FROM domains_dnsdomainmetadata \
WHERE domain_id=( \
SELECT id FROM domains_dnsdomain \
WHERE domain=E'%s' \
)
gpgsql-clear-domain-metadata-query=DELETE FROM domains_dnsdomainmetadata \
WHERE domain_id=( \
SELECT id FROM domains_dnsdomain \
WHERE domain=E'%s' \
) AND domains_dnsdomainmetadata.kind=E'%s'
gpgsql-get-all-domain-metadata-query=SELECT kind, content \
FROM domains_dnsdomain, domains_dnsdomainmetadata \
WHERE domains_dnsdomainmetadata.domain_id=domains_dnsdomain.id AND domain=E'%s'
gpgsql-get-domain-metadata-query=SELECT content \
FROM domains_dnsdomain, domains_dnsdomainmetadata \
WHERE domains_dnsdomainmetadata.domain_id=domains_dnsdomain.id AND domain=E'%s' AND domains_dnsdomainmetadata.kind=E'%s'
gpgsql-set-domain-metadata-query=INSERT INTO domains_dnsdomainmetadata \
(domain_id, kind, content) \
SELECT id, '%s', '%s' FROM domains_dnsdomain \
WHERE domain=E'%s'
# Record queries
gpgsql-delete-empty-non-terminal-query=DELETE FROM domains_dnsrecord \
WHERE domain_id='%d' AND name='%s' AND type IS NULL
gpgsql-delete-names-query=DELETE FROM domains_dnsrecord \
WHERE domain_id=%d AND name=E'%s'
gpgsql-delete-rrset-query=DELETE FROM domains_dnsrecord \
WHERE domain_id=%d AND name=E'%s' AND type=E'%s'
gpgsql-get-order-after-query=SELECT ordername FROM domains_dnsrecord \
WHERE disabled=false AND ordername ~>~ E'%s' AND domain_id=%d AND ordername IS NOT NULL \
ORDER BY 1 USING ~<~ LIMIT 1
gpgsql-get-order-before-query=SELECT ordername, name FROM domains_dnsrecord \
WHERE disabled=false AND ordername ~<=~ E'%s' AND domain_id=%d AND ordername IS NOT NULL \
ORDER BY 1 USING ~>~ LIMIT 1
gpgsql-get-order-first-query=SELECT ordername, name FROM domains_dnsrecord \
WHERE disabled=false AND domain_id=%d AND ordername IS NOT NULL \
ORDER BY 1 USING ~<~ LIMIT 1
gpgsql-get-order-last-query=SELECT ordername, name FROM domains_dnsrecord \
WHERE disabled=false AND ordername != '' AND domain_id=%d AND ordername IS NOT NULL \
ORDER BY 1 USING ~>~ LIMIT 1
gpgsql-insert-empty-non-terminal-query=INSERT INTO domains_dnsrecord \
(domain_id, name, type, disabled, auth) \
VALUES ('%d', '%s', null, false, true)
gpgsql-insert-ent-order-query=INSERT INTO domains_dnsrecord \
(type, domain_id, disabled, name, ordername, auth) \
VALUES (null, '%d', false, E'%s', E'%s', '%d')
gpgsql-insert-ent-query=INSERT INTO domains_dnsrecord \
(type, domain_id, disabled, name, auth) \
VALUES (null, '%d', false, E'%s', '%d')
gpgsql-insert-record-order-query=INSERT INTO domains_dnsrecord \
(content, ttl, prio, type, domain_id, disabled, name, ordername, auth) \
VALUES (E'%s', %d, %d, '%s', %d, %d::bool, E'%s', E'%s', '%d')
gpgsql-list-subzone-query=SELECT content, ttl, prio, type, domain_id, disabled::int, name, auth::int \
FROM domains_dnsrecord \
WHERE disabled=false AND (name=E'%s' OR name like E'%s') AND domain_id='%d'
gpgsql-nullify-ordername-and-auth-query=UPDATE domains_dnsrecord \
SET ordername=NULL, auth=false \
WHERE name=E'%s' AND type=E'%s' AND domain_id='%d' AND disabled=false
gpgsql-nullify-ordername-and-update-auth-query=UPDATE domains_dnsrecord \
SET ordername=NULL, auth=%d::bool \
WHERE domain_id='%d' AND name='%s' AND disabled=false
gpgsql-remove-empty-non-terminals-from-zone-query=DELETE FROM domains_dnsrecord \
WHERE domain_id='%d' AND type IS NULL
gpgsql-set-auth-on-ds-record-query=UPDATE domains_dnsrecord \
SET auth=true \
WHERE domain_id='%d' AND name='%s' AND type='DS' AND disabled=false
gpgsql-set-order-and-auth-query=UPDATE domains_dnsrecord \
SET ordername=E'%s', auth=%d::bool \
WHERE name=E'%s' AND domain_id='%d' AND disabled=false
gpgsql-zone-lastchange-query=SELECT MAX(change_date) FROM domains_dnsrecord \
WHERE domain_id=%d
# Domain queries
gpgsql-delete-domain-query=DELETE FROM domains_dnsdomain \
WHERE domain=E'%s'
gpgsql-insert-zone-query=INSERT INTO domains_dnsdomain \
(type, domain) \
VALUES ('NATIVE', E'%s')
gpgsql-update-kind-query=UPDATE domains_dnsdomain \
SET type='%s' \
WHERE domain='%s'
gpgsql-update-master-query=UPDATE domains_dnsdomain \
SET master='%s' \
WHERE domain='%s'
# Mixed queries
gpgsql-get-all-domains-query=SELECT domains_dnsdomain.id, domains_dnsdomain.domain, domains_dnsrecord.content, \
domains_dnsdomain.type, domains_dnsdomain.master, domains_dnsdomain.notified_serial, domains_dnsdomain.last_check \
FROM domains_dnsdomain \
LEFT JOIN domains_dnsrecord \
ON domains_dnsrecord.domain_id=domains_dnsdomain.id AND domains_dnsrecord.type='SOA' AND domains_dnsrecord.name=domains_dnsdomain.domain \
WHERE domains_dnsrecord.disabled=false OR %d::bool

35
docs/task_flows.rst Normal file
View file

@ -0,0 +1,35 @@
**********
Task Flows
**********
gva uses Celery tasks to trigger actions on several servers, this chapter lists
the code parts that start tasks. See the code documentation for details on the
information flow.
:py:mod:`osusers.admin`
=======================
* :py:meth:`osusers.admin.SshPublicKeyAdmin.perform_delete_selected`
:py:mod:`osusers.signals`
=========================
* :py:func:`osusers.signals.handle_group_created`
* :py:func:`osusers.signals.handle_group_deleted`
* :py:func:`osusers.signals.handle_ssh_keys_changed`
* :py:func:`osusers.signals.handle_user_added_to_group`
* :py:func:`osusers.signals.handle_user_created`
* :py:func:`osusers.signals.handle_user_deleted`
* :py:func:`osusers.signals.handle_user_password_set`
* :py:func:`osusers.signals.handle_user_removed_from_group`
:py:mod:`userdbs.signals`
=========================
* :py:func:`userdbs.signals.handle_dbuser_created`
* :py:func:`userdbs.signals.handle_dbuser_deleted`
* :py:func:`userdbs.signals.handle_dbuser_deleted`
* :py:func:`userdbs.signals.handle_dbuser_password_set`
* :py:func:`userdbs.signals.handle_userdb_created`

7
entrypoint.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
set -e
chown -Rc gva.gva /srv/gva/media /srv/gva/static
su -c /srv/gva.sh gva

View file

@ -0,0 +1,227 @@
[
{
"fields": {
"description": "",
"diskspace": 256,
"created": "2015-01-18T10:50:38.392Z",
"modified": "2015-01-18T10:50:38.409Z",
"diskspace_unit": 0,
"mailboxcount": 10,
"name": "Basispaket I"
},
"model": "hostingpackages.hostingpackagetemplate",
"pk": 1
},
{
"fields": {
"description": "",
"diskspace": 512,
"created": "2015-01-18T10:50:55.413Z",
"modified": "2015-01-18T10:50:55.425Z",
"diskspace_unit": 0,
"mailboxcount": 25,
"name": "Basispaket II"
},
"model": "hostingpackages.hostingpackagetemplate",
"pk": 2
},
{
"fields": {
"description": "",
"diskspace": 1,
"created": "2015-01-18T10:51:13.988Z",
"modified": "2015-01-18T10:51:13.999Z",
"diskspace_unit": 1,
"mailboxcount": 50,
"name": "Basispaket III"
},
"model": "hostingpackages.hostingpackagetemplate",
"pk": 3
},
{
"fields": {
"description": "Hostingpaket, dass ausschlie\u00dflich Mailweiterleitungen und Web-Redirects enth\u00e4lt",
"diskspace": 0,
"created": "2015-01-28T20:45:20.598Z",
"modified": "2015-01-28T20:45:20.616Z",
"diskspace_unit": 0,
"mailboxcount": 0,
"name": "Weiterleitung an externe Services"
},
"model": "hostingpackages.hostingpackagetemplate",
"pk": 4
},
{
"fields": {
"diskspace_unit": 0,
"diskspace": 256
},
"model": "hostingpackages.diskspaceoption",
"pk": 3
},
{
"fields": {
"diskspace_unit": 0,
"diskspace": 512
},
"model": "hostingpackages.diskspaceoption",
"pk": 4
},
{
"fields": {
"diskspace_unit": 1,
"diskspace": 1
},
"model": "hostingpackages.diskspaceoption",
"pk": 5
},
{
"fields": {
"diskspace_unit": 1,
"diskspace": 2
},
"model": "hostingpackages.diskspaceoption",
"pk": 6
},
{
"fields": {
"diskspace_unit": 1,
"diskspace": 5
},
"model": "hostingpackages.diskspaceoption",
"pk": 7
},
{
"fields": {
"diskspace_unit": 1,
"diskspace": 10
},
"model": "hostingpackages.diskspaceoption",
"pk": 8
},
{
"fields": {
"db_type": 0,
"number": 1
},
"model": "hostingpackages.userdatabaseoption",
"pk": 1
},
{
"fields": {
"db_type": 1,
"number": 1
},
"model": "hostingpackages.userdatabaseoption",
"pk": 2
},
{
"fields": {
"number": 10
},
"model": "hostingpackages.mailboxoption",
"pk": 9
},
{
"fields": {
"number": 25
},
"model": "hostingpackages.mailboxoption",
"pk": 10
},
{
"fields": {
"number": 50
},
"model": "hostingpackages.mailboxoption",
"pk": 11
},
{
"fields": {
"modified": "2015-01-18T10:51:38.298Z",
"created": "2015-01-18T10:51:38.286Z"
},
"model": "hostingpackages.hostingoption",
"pk": 1
},
{
"fields": {
"modified": "2015-01-18T10:51:41.804Z",
"created": "2015-01-18T10:51:41.792Z"
},
"model": "hostingpackages.hostingoption",
"pk": 2
},
{
"fields": {
"modified": "2015-01-18T10:52:03.193Z",
"created": "2015-01-18T10:52:03.181Z"
},
"model": "hostingpackages.hostingoption",
"pk": 3
},
{
"fields": {
"modified": "2015-01-18T10:52:08.430Z",
"created": "2015-01-18T10:52:08.418Z"
},
"model": "hostingpackages.hostingoption",
"pk": 4
},
{
"fields": {
"modified": "2015-01-18T10:52:14.153Z",
"created": "2015-01-18T10:52:14.134Z"
},
"model": "hostingpackages.hostingoption",
"pk": 5
},
{
"fields": {
"modified": "2015-01-18T10:52:19.151Z",
"created": "2015-01-18T10:52:19.138Z"
},
"model": "hostingpackages.hostingoption",
"pk": 6
},
{
"fields": {
"modified": "2015-01-18T10:52:24.461Z",
"created": "2015-01-18T10:52:24.448Z"
},
"model": "hostingpackages.hostingoption",
"pk": 7
},
{
"fields": {
"modified": "2015-01-18T10:52:30.821Z",
"created": "2015-01-18T10:52:30.807Z"
},
"model": "hostingpackages.hostingoption",
"pk": 8
},
{
"fields": {
"modified": "2015-01-18T10:52:53.657Z",
"created": "2015-01-18T10:52:53.646Z"
},
"model": "hostingpackages.hostingoption",
"pk": 9
},
{
"fields": {
"modified": "2015-01-18T10:52:56.079Z",
"created": "2015-01-18T10:52:56.064Z"
},
"model": "hostingpackages.hostingoption",
"pk": 10
},
{
"fields": {
"modified": "2015-01-18T10:53:01.634Z",
"created": "2015-01-18T10:53:01.622Z"
},
"model": "hostingpackages.hostingoption",
"pk": 11
}
]

View file

@ -0,0 +1,46 @@
[
{
"fields": {
"created": "2014-06-03T10:13:59.796Z",
"descr": "SFTP users",
"groupname": "sftponly",
"modified": "2014-06-03T10:13:59.804Z",
"passwd": ""
},
"model": "osusers.group",
"pk": 2000
},
{
"fields": {
"created": "2014-06-03T10:14:14.353Z",
"descr": "",
"groupname": "wwwusers",
"modified": "2014-06-03T10:14:14.360Z",
"passwd": ""
},
"model": "osusers.group",
"pk": 2001
},
{
"fields": {
"created": "2014-06-03T10:14:31.853Z",
"descr": "",
"groupname": "webserver",
"modified": "2014-06-03T10:14:31.860Z",
"passwd": ""
},
"model": "osusers.group",
"pk": 2002
},
{
"fields": {
"created": "2016-06-18T10:32:26.490Z",
"descr": "Group for git only access",
"groupname": "gitonly",
"modified": "2016-06-18T10:32:26.498Z",
"passwd": ""
},
"model": "osusers.group",
"pk": 2003
}
]

1
frontend/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules/

46
frontend/package-lock.json generated Normal file
View file

@ -0,0 +1,46 @@
{
"name": "frontend",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"bootstrap": "^5.2.3",
"bootstrap-icons": "^1.10.4"
}
},
"node_modules/@popperjs/core": {
"version": "2.11.7",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz",
"integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/bootstrap": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz",
"integrity": "sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"peerDependencies": {
"@popperjs/core": "^2.11.6"
}
},
"node_modules/bootstrap-icons": {
"version": "1.10.4",
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.4.tgz",
"integrity": "sha512-eI3HyIUmpGKRiRv15FCZccV+2sreGE2NnmH8mtxV/nPOzQVu0sPEj8HhF1MwjJ31IhjF0rgMvtYOX5VqIzcb/A=="
}
}
}

6
frontend/package.json Normal file
View file

@ -0,0 +1,6 @@
{
"dependencies": {
"bootstrap": "^5.2.3",
"bootstrap-icons": "^1.10.4"
}
}

View file

@ -1,5 +0,0 @@
[run]
source = gnuviechadmin,managemails,osusers,domains
[report]
omit = */migrations/*,*/tests/*.py,*/tests.py,gnuviechadmin/settings/local.py,gnuviechadmin/settings/production.py

View file

@ -0,0 +1,4 @@
"""
Contact form app.
"""

View file

@ -0,0 +1,73 @@
"""
This module contains the form class for the contact_form app.
"""
from __future__ import absolute_import, unicode_literals
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from django import forms
from django.apps import apps
from django.conf import settings
from django.contrib.sites.models import Site
from django.contrib.sites.requests import RequestSite
from django.core.mail import send_mail
from django.template import RequestContext, loader
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
class ContactForm(forms.Form):
"""
This is the contact form class.
"""
name = forms.CharField(max_length=100, label=_("Your name"))
email = forms.EmailField(max_length=200, label=_("Your email address"))
body = forms.CharField(widget=forms.Textarea, label=_("Your message"))
subject_template_name = "contact_form/contact_form_subject.txt"
template_name = "contact_form/contact_form.txt"
from_email = settings.DEFAULT_FROM_EMAIL
recipient_list = [mail_tuple[1] for mail_tuple in settings.MANAGERS]
def __init__(self, **kwargs):
self.request = kwargs.pop("request")
super(ContactForm, self).__init__(**kwargs)
self.helper = FormHelper()
self.helper.form_action = reverse("contact_form")
self.helper.add_input(Submit("submit", _("Send message")))
def get_context(self):
if not self.is_valid():
raise ValueError("Cannot generate context from invalid contact form")
if apps.is_installed("django.contrib.sites"):
site = Site.objects.get_current()
else:
site = RequestSite(self.request)
return RequestContext(self.request, dict(self.cleaned_data, site=site))
def message(self):
context = self.get_context()
template_context = context.flatten()
template_context.update({"remote_ip": context.request.META["REMOTE_ADDR"]})
return loader.render_to_string(self.template_name, template_context)
def subject(self):
context = self.get_context().flatten()
subject = loader.render_to_string(self.subject_template_name, context)
return "".join(subject.splitlines())
def save(self, fail_silently=False):
"""
Build and send the email.
"""
send_mail(
fail_silently=fail_silently,
from_email=self.from_email,
recipient_list=self.recipient_list,
subject=self.subject(),
message=self.message(),
)

View file

@ -0,0 +1,47 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: contact_form\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-22 19:45+0200\n"
"PO-Revision-Date: 2023-04-22 13:01+0200\n"
"Last-Translator: Jan Dittberner <jan@dittberner.info>\n"
"Language-Team: Jan Dittberner <jan@dittberner.info>\n"
"Language: de\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"
"X-Generator: Poedit 3.2.2\n"
"X-Poedit-SourceCharset: UTF-8\n"
#: contact_form/forms.py:26
msgid "Your name"
msgstr "Ihr Name"
#: contact_form/forms.py:27
msgid "Your email address"
msgstr "Ihre E-Mail-Adresse"
#: contact_form/forms.py:28
msgid "Your message"
msgstr "Ihre Nachricht"
#: contact_form/forms.py:40
msgid "Send message"
msgstr "Nachricht senden"
#: contact_form/templates/contact_form/contact_form.html:4
#: contact_form/templates/contact_form/contact_form.html:5
#: contact_form/templates/contact_form/contact_success.html:4
#: contact_form/templates/contact_form/contact_success.html:5
msgid "Contact"
msgstr "Kontakt"
#: contact_form/templates/contact_form/contact_success.html:8
msgid "Your message has been sent successfully."
msgstr "Ihre Nachricht wurde erfolgreich übermittelt."

View file

@ -0,0 +1 @@
{% extends "base.html" %}

View file

@ -0,0 +1,23 @@
{% extends "contact_form/base.html" %}
{% load i18n crispy_forms_tags %}
{% block title %}{{ block.super }} - {% translate "Contact" %}{% endblock title %}
{% block page_title %}{% translate "Contact" %}{% endblock page_title %}
{% block content %}
{% crispy form %}
{% endblock %}
{% block extra_js %}
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function () {
let textFields = document.querySelectorAll("input[type=text]");
if (textFields[0].val() !== '') {
document.getElementsByTagName("textarea")[0].focus();
} else {
textFields[0].focus();
}
});
</script>
{% endblock extra_js %}

View file

@ -0,0 +1,5 @@
User {{ name }} <{{ email }}> from IP address {{ remote_ip }}
sent the following message via the contact form at
{{ site }}{% url 'contact_form' %}:
{{ body }}

View file

@ -0,0 +1 @@
[{{ site.name }}] message from {{ name }} via contact form

View file

@ -0,0 +1,9 @@
{% extends "contact_form/base.html" %}
{% load i18n %}
{% block title %}{{ block.super }} - {% translate "Contact" %}{% endblock title %}
{% block page_title %}{% translate "Contact" %}{% endblock page_title %}
{% block content %}
<p class="text-success">{% translate "Your message has been sent successfully." %}</p>
{% endblock %}

View file

@ -0,0 +1,4 @@
"""
Tests for the :py:mod:`contact_form` app.
"""

View file

@ -0,0 +1,83 @@
"""
Tests for :py:mod:`contact_form.forms`.
"""
from unittest.mock import MagicMock, Mock, patch
from django.contrib.sites.models import Site
from django.test import TestCase
from django.urls import reverse
from contact_form.forms import ContactForm
TEST_DATA = {"name": "Test User", "email": "test@example.org", "body": "Test message"}
class ContactFormTest(TestCase):
def test_constructor_needs_request(self):
with self.assertRaises(KeyError):
ContactForm()
def test_constructor(self):
request = MagicMock()
form = ContactForm(request=request)
self.assertTrue(hasattr(form, "request"))
self.assertEqual(form.request, request)
self.assertTrue(hasattr(form, "helper"))
self.assertEqual(form.helper.form_action, reverse("contact_form"))
self.assertEqual(len(form.helper.inputs), 1)
self.assertEqual(form.helper.inputs[0].name, "submit")
def test_constructor_fields(self):
request = MagicMock()
form = ContactForm(request=request)
self.assertEqual(len(form.fields), 3)
self.assertIn("email", form.fields)
self.assertIn("name", form.fields)
self.assertIn("body", form.fields)
self.assertEqual(len(form.data), 0)
def test_get_context_invalid(self):
request = MagicMock()
form = ContactForm(request=request)
with self.assertRaisesMessage(
ValueError, "Cannot generate context from invalid contact form"
):
form.get_context()
def test_get_context_valid_site_installed(self):
request = MagicMock()
form = ContactForm(request=request, data=TEST_DATA)
context = form.get_context()
self.assertIn("site", context)
self.assertIn("name", context)
self.assertIn("email", context)
self.assertIn("body", context)
def test_get_context_valid_site_not_installed(self):
request = MagicMock()
form = ContactForm(request=request, data=TEST_DATA)
with patch("contact_form.forms.Site") as sitemock:
sitemock._meta.installed = False
context = form.get_context()
self.assertIn("site", context)
self.assertIn("name", context)
self.assertIn("email", context)
self.assertIn("body", context)
def test_message(self):
request = Mock()
request.META = {"REMOTE_ADDR": "127.0.0.1"}
form = ContactForm(request=request, data=TEST_DATA)
message = form.message()
self.assertIn(TEST_DATA["name"], message)
self.assertIn(TEST_DATA["email"], message)
self.assertIn(TEST_DATA["body"], message)
self.assertIn("127.0.0.1", message)
def test_subject(self):
request = Mock()
form = ContactForm(request=request, data=TEST_DATA)
subject = form.subject()
self.assertIn(Site.objects.get_current().name, subject)
self.assertIn(TEST_DATA["name"], subject)

View file

@ -0,0 +1,123 @@
"""
Tests for :py:mod:`contact_form.views`.
"""
from django.contrib.auth import get_user_model
from django.core import mail
from django.test import TestCase
from django.urls import reverse
User = get_user_model()
TEST_USER = "test"
TEST_PASSWORD = "secret"
TEST_EMAIL = "test@example.org"
TEST_NAME = "Example Tester".split()
TEST_MESSAGE = """
This is a really unimportant test message.
"""
class ContactFormViewTest(TestCase):
def _setup_user(self, **kwargs):
return User.objects.create_user(
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD, **kwargs
)
def test_get_contact_form_template(self):
response = self.client.get(reverse("contact_form"))
self.assertTemplateUsed(response, "contact_form/contact_form.html")
def test_get_contact_form_anonymous_status(self):
response = self.client.get(reverse("contact_form"))
self.assertEqual(response.status_code, 200)
def test_get_contact_form_anonymous_has_empty_form(self):
response = self.client.get(reverse("contact_form"))
self.assertIn("form", response.context)
form = response.context["form"]
self.assertEqual(len(form.initial), 0)
def test_get_contact_form_fields_anonymous(self):
response = self.client.get(reverse("contact_form"))
for name in ("name", "email", "body"):
self.assertIn(name, response.context["form"].fields)
def test_post_empty_form_template(self):
response = self.client.post(reverse("contact_form"), {})
self.assertTemplateUsed(response, "contact_form/contact_form.html")
def test_post_empty_form_status(self):
response = self.client.post(reverse("contact_form"), {})
self.assertEqual(response.status_code, 200)
def test_post_empty_form_validation_errors(self):
response = self.client.post(reverse("contact_form"), {})
self.assertIn("form", response.context)
form = response.context["form"]
self.assertFalse(form.is_valid())
self.assertEqual(len(form.errors), 3)
def test_post_empty_form_no_mail(self):
self.client.post(reverse("contact_form"), {})
self.assertEqual(len(mail.outbox), 0)
def test_get_contact_form_logged_in_no_fullname_initial(self):
self._setup_user()
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.get(reverse("contact_form"))
self.assertIn("form", response.context)
form = response.context["form"]
self.assertEqual(form.initial, {"name": TEST_USER, "email": TEST_EMAIL})
def test_get_contact_form_logged_in_fullname_initial(self):
self._setup_user(first_name=TEST_NAME[0], last_name=TEST_NAME[1])
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.get(reverse("contact_form"))
self.assertIn("form", response.context)
form = response.context["form"]
self.assertEqual(
form.initial, {"name": " ".join(TEST_NAME), "email": TEST_EMAIL}
)
def test_post_filled_form_anonymous_redirects(self):
response = self.client.post(
reverse("contact_form"),
{"name": TEST_USER, "email": TEST_EMAIL, "body": TEST_MESSAGE},
)
self.assertRedirects(response, reverse("contact_success"))
def test_post_filled_form_anonymous_mail(self):
self.client.post(
reverse("contact_form"),
{"name": TEST_USER, "email": TEST_EMAIL, "body": TEST_MESSAGE},
)
self.assertEqual(len(mail.outbox), 1)
def test_post_filled_form_logged_in_redirects(self):
self._setup_user(first_name=TEST_NAME[0], last_name=TEST_NAME[1])
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.post(
reverse("contact_form"),
{"name": " ".join(TEST_NAME), "email": TEST_EMAIL, "body": TEST_MESSAGE},
)
self.assertRedirects(response, reverse("contact_success"))
def test_post_filled_form_logged_in_mail(self):
self._setup_user(first_name=TEST_NAME[0], last_name=TEST_NAME[1])
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
self.client.post(
reverse("contact_form"),
{"name": " ".join(TEST_NAME), "email": TEST_EMAIL, "body": TEST_MESSAGE},
)
self.assertEqual(len(mail.outbox), 1)
class ContactSuccessViewTest(TestCase):
def test_get_template(self):
response = self.client.get(reverse("contact_success"))
self.assertTemplateUsed(response, "contact_form/contact_success.html")
def test_get_status(self):
response = self.client.get(reverse("contact_success"))
self.assertEqual(response.status_code, 200)

View file

@ -0,0 +1,14 @@
"""
URL patterns for the contact_form views.
"""
from __future__ import absolute_import
from django.urls import re_path
from .views import ContactFormView, ContactSuccessView
urlpatterns = [
re_path(r"^$", ContactFormView.as_view(), name="contact_form"),
re_path(r"^success/$", ContactSuccessView.as_view(), name="contact_success"),
]

View file

@ -0,0 +1,48 @@
"""
This module defines the views of the contact_form app.
"""
from __future__ import absolute_import
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.views.generic import FormView, TemplateView
from .forms import ContactForm
class ContactFormView(FormView):
"""
This is the contact form view.
"""
form_class = ContactForm
template_name = "contact_form/contact_form.html"
success_url = reverse_lazy("contact_success")
def get_form_kwargs(self, **kwargs):
kwargs = super(ContactFormView, self).get_form_kwargs(**kwargs)
kwargs["request"] = self.request
return kwargs
def get_initial(self):
initial = super(ContactFormView, self).get_initial()
currentuser = self.request.user
if currentuser.is_authenticated:
initial["name"] = currentuser.get_full_name() or currentuser.username
initial["email"] = currentuser.email
return initial
def form_valid(self, form):
form.save(False)
return redirect(self.get_success_url())
class ContactSuccessView(TemplateView):
"""
This view is shown after successful contact form sending.
"""
template_name = "contact_form/contact_success.html"

View file

@ -0,0 +1,4 @@
"""
This app contains the customer dashboard implementation for gnuviechadmin.
"""

View file

@ -0,0 +1,59 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: gnuviechadmin dashboard\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-22 19:45+0200\n"
"PO-Revision-Date: 2023-07-22 19:46+0200\n"
"Last-Translator: Jan Dittberner <jan@dittberner.info>\n"
"Language-Team: Jan Dittberner <jan@dittberner.info>\n"
"Language: de\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"
"X-Generator: Poedit 3.2.2\n"
"X-Poedit-SourceCharset: UTF-8\n"
#: dashboard/templates/dashboard/user_dashboard.html:3
#: dashboard/templates/dashboard/user_dashboard.html:6
#, python-format
msgid "Dashboard for %(full_name)s"
msgstr "Startseite für %(full_name)s"
#: dashboard/templates/dashboard/user_dashboard.html:10
msgid "Hosting packages"
msgstr "Hostingpakete"
#: dashboard/templates/dashboard/user_dashboard.html:17
msgid "Name"
msgstr "Name"
#: dashboard/templates/dashboard/user_dashboard.html:18
msgid "Setup date"
msgstr "Einrichtungsdatum"
#: dashboard/templates/dashboard/user_dashboard.html:19
msgid "Actions"
msgstr "Aktionen"
#: dashboard/templates/dashboard/user_dashboard.html:26
#, python-format
msgid "Show details for %(packagename)s"
msgstr "Details für %(packagename)s anzeigen"
#: dashboard/templates/dashboard/user_dashboard.html:38
msgid "You have no hosting packages yet."
msgstr "Sie haben noch keine Hostingpakete."
#: dashboard/templates/dashboard/user_dashboard.html:39
msgid "This user has no hosting packages assigned yet."
msgstr "Diesem Benutzer sind noch keine Hostingpakete zugewiesen."
#: dashboard/templates/dashboard/user_dashboard.html:43
msgid "Add hosting package"
msgstr "Hostingpaket anlegen"

View file

View file

@ -0,0 +1,47 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{{ block.super }} - {% blocktranslate with full_name=request.user.get_full_name trimmed %}
Dashboard for {{ full_name }}
{% endblocktranslate %}{% endblock title %}
{% block page_title %}{% blocktranslate with full_name=request.user.get_full_name trimmed %}
Dashboard for {{ full_name }}
{% endblocktranslate %}{% endblock page_title %}
{% block content %}
<h2>{% translate "Hosting packages" %}</h2>
<div class="row">
<div class="col-12">
{% if hosting_packages %}
<table class="table">
<thead>
<tr>
<th>{% translate "Name" %}</th>
<th>{% translate "Setup date" %}</th>
<th>{% translate "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for package in hosting_packages %}
<tr>
<td><a href="{{ package.get_absolute_url }}"
title="{% blocktranslate with packagename=package.name trimmed %}
Show details for {{ packagename }}
{% endblocktranslate %}">{{ package.name }}</a>
</td>
<td>{{ package.created }}</td>
<td></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="text-info">
{% if user == object %}{% translate "You have no hosting packages yet." %}{% else %}
{% translate "This user has no hosting packages assigned yet." %}{% endif %}</p>
{% endif %}
{% if user.is_staff %}
<a href="{% url "create_customer_hosting_package" user=request.user.username %}"
class="btn btn-primary">{% translate "Add hosting package" %}</a>
{% endif %}
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,4 @@
"""
Tests for :py:mod:`dashboard`.
"""

View file

@ -0,0 +1,47 @@
"""
Tests for :py:mod:`dashboard.views`.
"""
from django import http
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
User = get_user_model()
TEST_USER = "test"
TEST_PASSWORD = "secret"
class UserDashboardViewTest(TestCase):
def _create_test_user(self):
self.user = User.objects.create(username=TEST_USER)
self.user.set_password(TEST_PASSWORD)
self.user.save()
def test_user_dashboard_view_anonymous(self):
User.objects.create(username=TEST_USER)
response = self.client.get(reverse("customer_dashboard"))
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, "/accounts/login/?next=/")
def test_user_dashboard_view_logged_in_ok(self):
self._create_test_user()
self.assertTrue(self.client.login(username=TEST_USER, password=TEST_PASSWORD))
response = self.client.get(reverse("customer_dashboard"))
self.assertEqual(response.status_code, 200)
def test_user_dashboard_view_logged_in_template(self):
self._create_test_user()
self.assertTrue(self.client.login(username=TEST_USER, password=TEST_PASSWORD))
response = self.client.get(
reverse("customer_dashboard")
)
self.assertTemplateUsed(response, "dashboard/user_dashboard.html")
def test_user_dashboard_view_logged_in_context_fresh(self):
self._create_test_user()
self.assertTrue(self.client.login(username=TEST_USER, password=TEST_PASSWORD))
response = self.client.get(reverse("customer_dashboard"))
self.assertIn("hosting_packages", response.context)
self.assertEqual(len(response.context["hosting_packages"]), 0)

View file

@ -0,0 +1,9 @@
from __future__ import absolute_import
from django.urls import path
from .views import UserDashboardView
urlpatterns = [
path("", UserDashboardView.as_view(), name="customer_dashboard"),
]

View file

@ -0,0 +1,27 @@
"""
This module defines the views for the gnuviechadmin customer dashboard.
"""
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import redirect
from django.views.generic import DetailView, TemplateView
from gvacommon.viewmixins import StaffOrSelfLoginRequiredMixin
from hostingpackages.models import CustomerHostingPackage
class UserDashboardView(LoginRequiredMixin, TemplateView):
"""
This is the user dashboard view.
"""
template_name = "dashboard/user_dashboard.html"
def get_context_data(self, **kwargs):
context = super(UserDashboardView, self).get_context_data(**kwargs)
context["hosting_packages"] = CustomerHostingPackage.objects.filter(
customer=self.request.user
)
return context

View file

@ -0,0 +1,4 @@
"""
This app takes care of domains.
"""

View file

@ -1,5 +1,11 @@
"""
This module registers the model classes defined in :py:mod:`domains.models`
with the django admin site.
"""
from django.contrib import admin
from .models import MailDomain
from domains.models import HostingDomain, MailDomain
admin.site.register(MailDomain)
admin.site.register(HostingDomain)

View file

@ -0,0 +1,17 @@
"""
This module contains the :py:class:`django.apps.AppConfig` instance for the
:py:mod:`domains` app.
"""
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class DomainAppConfig(AppConfig):
"""
AppConfig for the :py:mod:`domains` app.
"""
name = "domains"
verbose_name = _("Domains")

View file

@ -0,0 +1,64 @@
"""
This module defines form classes for domain editing.
"""
from __future__ import absolute_import
import re
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit
from django import forms
from django.urls import reverse
from django.utils.translation import gettext as _
from .models import HostingDomain
def relative_domain_validator(value):
"""
This validator ensures that the given value is a valid lowercase domain
name.
"""
if len(value) > 254:
raise forms.ValidationError(_("host name too long"), code="too-long")
allowed = re.compile(r"(?!-)[a-z\d-]{1,63}(?<!-)$")
if not all(allowed.match(x) for x in value.split(".")):
raise forms.ValidationError(_("invalid domain name"))
class CreateHostingDomainForm(forms.ModelForm):
"""
This form is used to create new HostingDomain instances.
"""
class Meta:
model = HostingDomain
fields = ["domain"]
def __init__(self, instance, *args, **kwargs):
self.hosting_package = kwargs.pop("hostingpackage")
super(CreateHostingDomainForm, self).__init__(*args, **kwargs)
self.fields["domain"].validators.append(relative_domain_validator)
self.helper = FormHelper()
self.helper.form_action = reverse(
"create_hosting_domain", kwargs={"package": self.hosting_package.id}
)
self.helper.layout = Layout(
"domain",
Submit("submit", _("Add Hosting Domain")),
)
def clean(self):
self.cleaned_data = super(CreateHostingDomainForm, self).clean()
self.cleaned_data["hosting_package"] = self.hosting_package
def save(self, commit=True):
return HostingDomain.objects.create_for_hosting_package(
commit=commit, **self.cleaned_data
)
def save_m2m(self):
pass

View file

@ -0,0 +1,75 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: gnuviechadmin domains\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-04-16 22:07+0200\n"
"PO-Revision-Date: 2023-04-16 18:20+0200\n"
"Last-Translator: Jan Dittberner <jan@dittberner.info>\n"
"Language-Team: Jan Dittberner <jan@dittberner.info>\n"
"Language: de\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"
"X-Generator: Poedit 3.2.2\n"
"X-Poedit-SourceCharset: UTF-8\n"
#: domains/apps.py:17
msgid "Domains"
msgstr "Domains"
#: domains/forms.py:25 domains/tests/test_forms.py:20
msgid "host name too long"
msgstr "zu langer Hostname"
#: domains/forms.py:28 domains/tests/test_forms.py:24
#: domains/tests/test_forms.py:28 domains/tests/test_forms.py:32
#: domains/tests/test_forms.py:36
msgid "invalid domain name"
msgstr "ungültiger Domainname"
#: domains/forms.py:51
msgid "Add Hosting Domain"
msgstr "Hostingdomain hinzufügen"
#: domains/models.py:19
msgid "domain name"
msgstr "Domainname"
#: domains/models.py:22
msgid "customer"
msgstr "Kunde"
#: domains/models.py:41
msgid "Mail domain"
msgstr "E-Maildomain"
#: domains/models.py:42
msgid "Mail domains"
msgstr "E-Maildomains"
#: domains/models.py:91
msgid "mail domain"
msgstr "E-Maildomain"
#: domains/models.py:94
msgid "assigned mail domain for this domain"
msgstr "zugeordnete E-Maildomain für diese Domain"
#: domains/models.py:101
msgid "Hosting domain"
msgstr "Hostingdomain"
#: domains/models.py:102
msgid "Hosting domains"
msgstr "Hostingdomains"
#: domains/views.py:51
#, python-brace-format
msgid "Successfully created domain {domainname}"
msgstr "Domain {domainname} erfolgreich angelegt"

View file

@ -1,28 +1,46 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.utils.timezone
import model_utils.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
]
dependencies = []
operations = [
migrations.CreateModel(
name='MailDomain',
name="MailDomain",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, verbose_name='created', editable=False)),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, verbose_name='modified', editable=False)),
('domain', models.CharField(unique=True, max_length=128)),
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
(
"created",
model_utils.fields.AutoCreatedField(
default=django.utils.timezone.now,
verbose_name="created",
editable=False,
),
),
(
"modified",
model_utils.fields.AutoLastModifiedField(
default=django.utils.timezone.now,
verbose_name="modified",
editable=False,
),
),
("domain", models.CharField(unique=True, max_length=128)),
],
options={
'verbose_name': 'Mail domain',
'verbose_name_plural': 'Mail domains',
"verbose_name": "Mail domain",
"verbose_name_plural": "Mail domains",
},
bases=(models.Model,),
),

View file

@ -0,0 +1,97 @@
# -*- coding: utf-8 -*-
import django.utils.timezone
import model_utils.fields
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("domains", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="HostingDomain",
fields=[
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
(
"created",
model_utils.fields.AutoCreatedField(
default=django.utils.timezone.now,
verbose_name="created",
editable=False,
),
),
(
"modified",
model_utils.fields.AutoLastModifiedField(
default=django.utils.timezone.now,
verbose_name="modified",
editable=False,
),
),
(
"domain",
models.CharField(
unique=True, max_length=128, verbose_name="domain name"
),
),
(
"customer",
models.ForeignKey(
verbose_name="customer",
blank=True,
to=settings.AUTH_USER_MODEL,
null=True,
on_delete=models.CASCADE,
),
),
(
"maildomain",
models.OneToOneField(
null=True,
to="domains.MailDomain",
blank=True,
help_text="assigned mail domain for this domain",
verbose_name="mail domain",
on_delete=models.CASCADE,
),
),
],
options={
"verbose_name": "Hosting domain",
"verbose_name_plural": "Hosting domains",
},
bases=(models.Model,),
),
migrations.AddField(
model_name="maildomain",
name="customer",
field=models.ForeignKey(
verbose_name="customer",
blank=True,
to=settings.AUTH_USER_MODEL,
null=True,
on_delete=models.CASCADE,
),
preserve_default=True,
),
migrations.AlterField(
model_name="maildomain",
name="domain",
field=models.CharField(
unique=True, max_length=128, verbose_name="domain name"
),
preserve_default=True,
),
]

View file

@ -0,0 +1,285 @@
# -*- coding: utf-8 -*-
import django.utils.timezone
import model_utils.fields
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("domains", "0002_auto_20150124_1909"),
]
operations = [
migrations.CreateModel(
name="DNSComment",
fields=[
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("name", models.CharField(max_length=255)),
("commenttype", models.CharField(max_length=10, db_column="type")),
("modified_at", models.IntegerField()),
("comment", models.CharField(max_length=65535)),
(
"customer",
models.ForeignKey(
verbose_name="customer",
to=settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
),
),
],
),
migrations.RunSQL(
"""ALTER TABLE domains_dnscomment ADD CONSTRAINT c_lowercase_name
CHECK (((name)::TEXT = LOWER((name)::TEXT)))"""
),
migrations.CreateModel(
name="DNSCryptoKey",
fields=[
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("flags", models.IntegerField()),
("active", models.BooleanField(default=True)),
("content", models.TextField()),
],
),
migrations.CreateModel(
name="DNSDomain",
fields=[
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
(
"created",
model_utils.fields.AutoCreatedField(
default=django.utils.timezone.now,
verbose_name="created",
editable=False,
),
),
(
"modified",
model_utils.fields.AutoLastModifiedField(
default=django.utils.timezone.now,
verbose_name="modified",
editable=False,
),
),
(
"domain",
models.CharField(
unique=True, max_length=255, verbose_name="domain name"
),
),
("master", models.CharField(max_length=128, null=True, blank=True)),
("last_check", models.IntegerField(null=True)),
(
"domaintype",
models.CharField(
max_length=6,
db_column="type",
choices=[
("MASTER", "Master"),
("SLAVE", "Slave"),
("NATIVE", "Native"),
],
),
),
("notified_serial", models.IntegerField(null=True)),
(
"customer",
models.ForeignKey(
verbose_name="customer",
blank=True,
to=settings.AUTH_USER_MODEL,
null=True,
on_delete=models.CASCADE,
),
),
],
options={
"verbose_name": "DNS domain",
"verbose_name_plural": "DNS domains",
},
),
migrations.RunSQL(
"""ALTER TABLE domains_dnsdomain ADD CONSTRAINT c_lowercase_name
CHECK (((domain)::TEXT = LOWER((domain)::TEXT)))"""
),
migrations.CreateModel(
name="DNSDomainMetadata",
fields=[
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("kind", models.CharField(max_length=32)),
("content", models.TextField()),
(
"domain",
models.ForeignKey(to="domains.DNSDomain", on_delete=models.CASCADE),
),
],
),
migrations.CreateModel(
name="DNSRecord",
fields=[
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
(
"name",
models.CharField(
db_index=True, max_length=255, null=True, blank=True
),
),
(
"recordtype",
models.CharField(
max_length=10, null=True, db_column="type", blank=True
),
),
("content", models.CharField(max_length=65535, null=True, blank=True)),
("ttl", models.IntegerField(null=True)),
("prio", models.IntegerField(null=True)),
("change_date", models.IntegerField(null=True)),
("disabled", models.BooleanField(default=False)),
("ordername", models.CharField(max_length=255)),
("auth", models.BooleanField(default=True)),
(
"domain",
models.ForeignKey(to="domains.DNSDomain", on_delete=models.CASCADE),
),
],
options={
"verbose_name": "DNS record",
"verbose_name_plural": "DNS records",
},
),
migrations.RunSQL(
"""ALTER TABLE domains_dnsrecord ADD CONSTRAINT c_lowercase_name
CHECK (((name)::TEXT = LOWER((name)::TEXT)))"""
),
migrations.RunSQL(
"""CREATE INDEX recordorder ON domains_dnsrecord (domain_id,
ordername text_pattern_ops)"""
),
migrations.CreateModel(
name="DNSSupermaster",
fields=[
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("ip", models.GenericIPAddressField()),
("nameserver", models.CharField(max_length=255)),
(
"customer",
models.ForeignKey(
verbose_name="customer",
to=settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
),
),
],
),
migrations.CreateModel(
name="DNSTSIGKey",
fields=[
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("name", models.CharField(max_length=255)),
("algorithm", models.CharField(max_length=50)),
("secret", models.CharField(max_length=255)),
],
),
migrations.RunSQL(
"""ALTER TABLE domains_dnstsigkey ADD CONSTRAINT c_lowercase_name
CHECK (((name)::TEXT = LOWER((name)::TEXT)))"""
),
migrations.AlterField(
model_name="hostingdomain",
name="domain",
field=models.CharField(
unique=True, max_length=255, verbose_name="domain name"
),
),
migrations.AlterField(
model_name="maildomain",
name="domain",
field=models.CharField(
unique=True, max_length=255, verbose_name="domain name"
),
),
migrations.AddField(
model_name="dnscryptokey",
name="domain",
field=models.ForeignKey(to="domains.DNSDomain", on_delete=models.CASCADE),
),
migrations.AddField(
model_name="dnscomment",
name="domain",
field=models.ForeignKey(to="domains.DNSDomain", on_delete=models.CASCADE),
),
migrations.AlterUniqueTogether(
name="dnssupermaster",
unique_together=set([("ip", "nameserver")]),
),
migrations.AlterUniqueTogether(
name="dnstsigkey",
unique_together=set([("name", "algorithm")]),
),
migrations.AlterIndexTogether(
name="dnsrecord",
index_together=set([("name", "recordtype")]),
),
migrations.AlterIndexTogether(
name="dnscomment",
index_together={("name", "commenttype"), ("domain", "modified_at")},
),
]

View file

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("domains", "0003_auto_20151105_2133"),
]
operations = [
migrations.AlterModelOptions(
name="dnscomment",
options={
"verbose_name": "DNS comment",
"verbose_name_plural": "DNS comments",
},
),
migrations.AlterModelOptions(
name="dnscryptokey",
options={
"verbose_name": "DNS crypto key",
"verbose_name_plural": "DNS crypto keys",
},
),
migrations.AlterModelOptions(
name="dnsdomainmetadata",
options={
"verbose_name": "DNS domain metadata item",
"verbose_name_plural": "DNS domain metadata items",
},
),
migrations.AlterModelOptions(
name="dnssupermaster",
options={
"verbose_name": "DNS supermaster",
"verbose_name_plural": "DNS supermasters",
},
),
migrations.AlterModelOptions(
name="dnstsigkey",
options={
"verbose_name": "DNS TSIG key",
"verbose_name_plural": "DNS TSIG keys",
},
),
migrations.AlterField(
model_name="dnsdomainmetadata",
name="kind",
field=models.CharField(
max_length=32,
choices=[
("ALLOW-DNSUPDATE-FROM", "ALLOW-DNSUPDATE-FROM"),
("ALSO-NOTIFY", "ALSO-NOTIFY"),
("AXFR-MASTER-TSIG", "AXFR-MASTER-TSIG"),
("AXFR-SOURCE", "AXFR-SOURCE"),
("FORWARD-DNSUPDATE", "FORWARD-DNSUPDATE"),
("GSS-ACCEPTOR-PRINCIPAL", "GSS-ACCEPTOR-PRINCIPAL"),
("GSS-ALLOW-AXFR-PRINCIPAL", "GSS-ALLOW-AXFR-PRINCIPAL"),
("LUA-AXFR-SCRIPT", "LUA-AXFR-SCRIPT"),
("NSEC3NARROW", "NSEC3NARROW"),
("NSEC3PARAM", "NSEC3PARAM"),
("PRESIGNED", "PRESIGNED"),
("PUBLISH_CDNSKEY", "PUBLISH_CDNSKEY"),
("PUBLISH_CDS", "PUBLISH_CDS"),
("SOA-EDIT", "SOA-EDIT"),
("SOA-EDIT-DNSUPDATE", "SOA-EDIT-DNSUPDATE"),
("TSIG-ALLOW-AXFR", "TSIG-ALLOW-AXFR"),
("TSIG-ALLOW-DNSUPDATE", "TSIG-ALLOW-DNSUPDATE"),
],
),
),
migrations.AlterField(
model_name="dnstsigkey",
name="algorithm",
field=models.CharField(
max_length=50,
choices=[
("hmac-md5", "HMAC MD5"),
("hmac-sha1", "HMAC SHA1"),
("hmac-sha224", "HMAC SHA224"),
("hmac-sha256", "HMAC SHA256"),
("hmac-sha384", "HMAC SHA384"),
("hmac-sha512", "HMAC SHA512"),
],
),
),
]

View file

@ -0,0 +1,74 @@
# Generated by Django 3.2.18 on 2023-04-15 09:53
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('domains', '0004_auto_20151107_1708'),
]
operations = [
migrations.AlterIndexTogether(
name='dnscomment',
index_together=None,
),
migrations.RemoveField(
model_name='dnscomment',
name='customer',
),
migrations.RemoveField(
model_name='dnscomment',
name='domain',
),
migrations.RemoveField(
model_name='dnscryptokey',
name='domain',
),
migrations.RemoveField(
model_name='dnsdomain',
name='customer',
),
migrations.RemoveField(
model_name='dnsdomainmetadata',
name='domain',
),
migrations.AlterIndexTogether(
name='dnsrecord',
index_together=None,
),
migrations.RemoveField(
model_name='dnsrecord',
name='domain',
),
migrations.AlterUniqueTogether(
name='dnssupermaster',
unique_together=None,
),
migrations.RemoveField(
model_name='dnssupermaster',
name='customer',
),
migrations.DeleteModel(
name='DNSTSIGKey',
),
migrations.DeleteModel(
name='DNSComment',
),
migrations.DeleteModel(
name='DNSCryptoKey',
),
migrations.DeleteModel(
name='DNSDomain',
),
migrations.DeleteModel(
name='DNSDomainMetadata',
),
migrations.DeleteModel(
name='DNSRecord',
),
migrations.DeleteModel(
name='DNSSupermaster',
),
]

View file

@ -1,17 +1,105 @@
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext as _
"""
This module contains models related to domain names.
"""
from __future__ import absolute_import
from django.conf import settings
from django.db import models, transaction
from django.utils.translation import gettext as _
from model_utils.models import TimeStampedModel
@python_2_unicode_compatible
class MailDomain(TimeStampedModel, models.Model):
domain = models.CharField(max_length=128, unique=True)
class DomainBase(TimeStampedModel):
"""
This is the base model for domains.
"""
domain = models.CharField(_("domain name"), max_length=255, unique=True)
customer = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_("customer"),
blank=True,
null=True,
on_delete=models.CASCADE,
)
class Meta:
verbose_name = _('Mail domain')
verbose_name_plural = _('Mail domains')
abstract = True
class MailDomain(DomainBase):
"""
This is the model for mail domains. Mail domains are used to configure the
mail servers (SMTP/IMAP/POP3). Mail addresses are assigned to these mail
domains.
"""
class Meta(DomainBase.Meta):
verbose_name = _("Mail domain")
verbose_name_plural = _("Mail domains")
def __str__(self):
return self.domain
def get_mailaddresses(self):
"""
Get a list of mail addresses assigned to this mail domain.
"""
return self.mailaddress_set.all()
mailaddresses = property(get_mailaddresses)
class HostingDomainManager(models.Manager):
"""
Default Manager for :py:class:`HostingDomain`.
"""
@transaction.atomic
def create_for_hosting_package(self, hosting_package, domain, commit, **kwargs):
from hostingpackages.models import CustomerHostingPackageDomain
hostingdomain = self.create(
customer=hosting_package.customer, domain=domain, **kwargs
)
hostingdomain.maildomain = MailDomain.objects.create(
customer=hosting_package.customer, domain=domain
)
custdomain = CustomerHostingPackageDomain.objects.create(
hosting_package=hosting_package, domain=hostingdomain
)
if commit:
hostingdomain.save()
custdomain.save()
return hostingdomain
class HostingDomain(DomainBase):
"""
This is the model for hosting domains. A hosting domain is linked to a
customer hosting account.
"""
maildomain = models.OneToOneField(
MailDomain,
verbose_name=_("mail domain"),
blank=True,
null=True,
help_text=_("assigned mail domain for this domain"),
on_delete=models.CASCADE,
)
objects = HostingDomainManager()
class Meta:
verbose_name = _("Hosting domain")
verbose_name_plural = _("Hosting domains")
def __str__(self):
return self.domain

View file

@ -1,8 +1,8 @@
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.urls import reverse
class TestMailDomainAdmin(TestCase):
def test_admin_for_maildomain(self):
admin_url = reverse('admin:domains_maildomain_changelist')
admin_url = reverse("admin:domains_maildomain_changelist")
self.assertIsNotNone(admin_url)

View file

@ -0,0 +1,99 @@
"""
Tests for :py:mod:`domains.forms`.
"""
from unittest.mock import MagicMock, Mock, patch
from django.forms import ValidationError
from django.test import TestCase
from django.urls import reverse
from django.utils.translation import gettext as _
from domains.forms import CreateHostingDomainForm, relative_domain_validator
class RelativeDomainValidatorTest(TestCase):
def test_valid_domainname(self):
relative_domain_validator("example.org")
def test_domain_name_too_long(self):
with self.assertRaisesMessage(ValidationError, _("host name too long")):
relative_domain_validator("e" * 255)
def test_domain_name_part_too_long(self):
with self.assertRaisesMessage(ValidationError, _("invalid domain name")):
relative_domain_validator("a" * 64 + ".org")
def test_domain_name_illegal_characters(self):
with self.assertRaisesMessage(ValidationError, _("invalid domain name")):
relative_domain_validator("eXampl3.org")
def test_domain_name_starts_with_dash(self):
with self.assertRaisesMessage(ValidationError, _("invalid domain name")):
relative_domain_validator("-example.org")
def test_domain_name_ends_with_dash(self):
with self.assertRaisesMessage(ValidationError, _("invalid domain name")):
relative_domain_validator("example-.org")
class CreateHostingDomainFormTest(TestCase):
def test_constructor_needs_hostingpackage(self):
instance = MagicMock()
with self.assertRaises(KeyError):
CreateHostingDomainForm(instance)
def test_constructor(self):
hostingpackage = Mock(id=42)
instance = MagicMock()
form = CreateHostingDomainForm(instance, hostingpackage=hostingpackage)
self.assertTrue(hasattr(form, "hosting_package"))
self.assertEqual(form.hosting_package, hostingpackage)
self.assertTrue(hasattr(form, "helper"))
self.assertEqual(
form.helper.form_action,
reverse("create_hosting_domain", kwargs={"package": 42}),
)
self.assertEqual(len(form.helper.layout.fields), 2)
self.assertEqual(form.helper.layout.fields[1].name, "submit")
def test_domain_field_has_relative_domain_validator(self):
hostingpackage = Mock(id=42)
instance = MagicMock()
form = CreateHostingDomainForm(instance, hostingpackage=hostingpackage)
self.assertIn(relative_domain_validator, form.fields["domain"].validators)
def test_clean(self):
hostingpackage = Mock(id=42)
instance = MagicMock()
form = CreateHostingDomainForm(
instance, hostingpackage=hostingpackage, data={"domain": "example.org"}
)
self.assertTrue(form.is_valid())
self.assertIn("hosting_package", form.cleaned_data)
self.assertEqual(hostingpackage, form.cleaned_data["hosting_package"])
def test_save(self):
hostingpackage = Mock(id=42)
instance = MagicMock()
form = CreateHostingDomainForm(
instance, hostingpackage=hostingpackage, data={"domain": "example.org"}
)
self.assertTrue(form.is_valid())
with patch("domains.forms.HostingDomain") as domain:
form.save()
domain.objects.create_for_hosting_package.assert_called_with(
commit=True, **form.cleaned_data
)
form.save(commit=False)
domain.objects.create_for_hosting_package.assert_called_with(
commit=False, **form.cleaned_data
)
def test_save_m2m(self):
hostingpackage = Mock(id=42)
instance = MagicMock()
form = CreateHostingDomainForm(
instance, hostingpackage=hostingpackage, data={"domain": "example.org"}
)
form.save_m2m()

View file

@ -1,9 +1,69 @@
from django.test import TestCase
"""
Tests for :py:mod:`domains.models`.
from domains.models import MailDomain
"""
from unittest.mock import patch
from django.test import TestCase
from django.contrib.auth import get_user_model
from domains.models import HostingDomain, MailDomain
from hostingpackages.models import CustomerHostingPackage, HostingPackageTemplate
User = get_user_model()
TEST_USER = "test"
class MailDomainTest(TestCase):
def test__str__(self):
md = MailDomain.objects.create(domain='example.org')
self.assertEqual(str(md), 'example.org')
def test___str__(self):
md = MailDomain.objects.create(domain="example.org")
self.assertEqual(str(md), "example.org")
def test_get_mailaddresses(self):
md = MailDomain.objects.create(domain="example.org")
from managemails.models import MailAddress
addrmock = MailAddress.objects.create(localpart="info", domain=md)
self.assertIn(addrmock, md.get_mailaddresses())
self.assertIn(addrmock, md.mailaddresses)
class HostingDomainManagerTest(TestCase):
def _setup_hosting_package(self):
template = HostingPackageTemplate.objects.create(
name="testpackagetemplate", mailboxcount=0, diskspace=1, diskspace_unit=0
)
customer = User.objects.create_user(username=TEST_USER)
package = CustomerHostingPackage.objects.create_from_template(
customer, template, "testpackage"
)
with patch("hostingpackages.models.settings") as hmsettings:
hmsettings.OSUSER_DEFAULT_GROUPS = []
package.save()
return package
def test_create_for_hosting_package_with_commit(self):
package = self._setup_hosting_package()
hostingdomain = HostingDomain.objects.create_for_hosting_package(
package, "example.org", True
)
self.assertIsNotNone(hostingdomain)
self.assertTrue(hostingdomain.customer, package.customer)
def test_create_for_hosting_package_no_commit(self):
package = self._setup_hosting_package()
hostingdomain = HostingDomain.objects.create_for_hosting_package(
package, "example.org", False
)
self.assertIsNotNone(hostingdomain)
self.assertTrue(hostingdomain.customer, package.customer)
class HostingDomainTest(TestCase):
def test___str__(self):
hostingdomain = HostingDomain(domain="test")
self.assertEqual(str(hostingdomain), "test")

View file

@ -0,0 +1,153 @@
"""
Tests for :py:mod:`domains.views`.
"""
from unittest.mock import MagicMock, patch
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from domains.views import CreateHostingDomain
from hostingpackages.models import CustomerHostingPackage, HostingPackageTemplate
User = get_user_model()
TEST_USER = "test"
TEST_PASSWORD = "secret"
TEST_EMAIL = "test@example.org"
TEST_NAME = "Example Tester".split()
class CreateHostingDomainTest(TestCase):
def _setup_hosting_package(self, customer):
template = HostingPackageTemplate.objects.create(
name="testpackagetemplate", mailboxcount=0, diskspace=1, diskspace_unit=0
)
package = CustomerHostingPackage.objects.create_from_template(
customer, template, "testpackage"
)
with patch("hostingpackages.models.settings") as hmsettings:
hmsettings.OSUSER_DEFAULT_GROUPS = []
package.save()
return package
def test_get_anonymous(self):
response = self.client.get(
reverse("create_hosting_domain", kwargs={"package": 1})
)
self.assertEqual(response.status_code, 403)
def test_get_regular_user(self):
customer = User.objects.create_user(
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD
)
package = self._setup_hosting_package(customer)
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.get(
reverse("create_hosting_domain", kwargs={"package": package.id})
)
self.assertEqual(response.status_code, 403)
def test_get_staff_user(self):
customer = User.objects.create_user("customer")
package = self._setup_hosting_package(customer)
User.objects.create_superuser(
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD
)
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.get(
reverse("create_hosting_domain", kwargs={"package": package.id})
)
self.assertEqual(response.status_code, 200)
def test_get_template(self):
customer = User.objects.create_user("customer")
package = self._setup_hosting_package(customer)
User.objects.create_superuser(
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD
)
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.get(
reverse("create_hosting_domain", kwargs={"package": package.id})
)
self.assertTemplateUsed(response, "domains/hostingdomain_create.html")
def test_get_no_package_found(self):
User.objects.create_superuser(
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD
)
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.get(
reverse("create_hosting_domain", kwargs={"package": 1})
)
self.assertEqual(response.status_code, 404)
def test_get_get_form_kwargs(self):
customer = User.objects.create_user("customer")
package = self._setup_hosting_package(customer)
User.objects.create_superuser(
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD
)
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
view = CreateHostingDomain(
request=MagicMock(), kwargs={"package": str(package.id)}
)
the_kwargs = view.get_form_kwargs()
self.assertIn("hostingpackage", the_kwargs)
self.assertEqual(the_kwargs["hostingpackage"], package)
def test_get_context_data_has_hosting_package(self):
customer = User.objects.create_user("customer")
package = self._setup_hosting_package(customer)
User.objects.create_superuser(
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD
)
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.get(
reverse("create_hosting_domain", kwargs={"package": package.id})
)
self.assertIn("hostingpackage", response.context)
self.assertEqual(response.context["hostingpackage"], package)
def test_get_context_data_has_customer(self):
customer = User.objects.create_user("customer")
package = self._setup_hosting_package(customer)
User.objects.create_superuser(
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD
)
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.get(
reverse("create_hosting_domain", kwargs={"package": package.id})
)
self.assertIn("customer", response.context)
self.assertEqual(response.context["customer"], customer)
def test_form_valid_redirect(self):
customer = User.objects.create_user("customer")
package = self._setup_hosting_package(customer)
User.objects.create_superuser(
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD
)
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.post(
reverse("create_hosting_domain", kwargs={"package": package.id}),
data={"domain": "example.org"},
)
self.assertRedirects(response, package.get_absolute_url())
def test_form_valid_message(self):
customer = User.objects.create_user("customer")
package = self._setup_hosting_package(customer)
User.objects.create_superuser(
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD
)
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.post(
reverse("create_hosting_domain", kwargs={"package": package.id}),
follow=True,
data={"domain": "example.org"},
)
messages = list(response.context["messages"])
self.assertEqual(len(messages), 1)
self.assertEqual("Successfully created domain example.org", str(messages[0]))

View file

@ -0,0 +1,17 @@
"""
This module defines the URL patterns for domain related views.
"""
from __future__ import absolute_import
from django.urls import re_path
from .views import CreateHostingDomain
urlpatterns = [
re_path(
r"^(?P<package>\d+)/create$",
CreateHostingDomain.as_view(),
name="create_hosting_domain",
),
]

View file

@ -0,0 +1,55 @@
"""
This module defines views related to domains.
"""
from __future__ import absolute_import
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.shortcuts import get_object_or_404, redirect
from django.utils.translation import gettext as _
from django.views.generic.edit import CreateView
from hostingpackages.models import CustomerHostingPackage
from .forms import CreateHostingDomainForm
from .models import HostingDomain
class CreateHostingDomain(PermissionRequiredMixin, CreateView):
"""
This view is used for creating a new HostingDomain instance for an existing
hosting package.
"""
model = HostingDomain
raise_exception = True
permission_required = 'domains.add_hostingdomain'
template_name_suffix = "_create"
form_class = CreateHostingDomainForm
def _get_hosting_package(self):
return get_object_or_404(CustomerHostingPackage, pk=int(self.kwargs["package"]))
def get_form_kwargs(self):
kwargs = super(CreateHostingDomain, self).get_form_kwargs()
kwargs["hostingpackage"] = self._get_hosting_package()
return kwargs
def get_context_data(self, **kwargs):
context = super(CreateHostingDomain, self).get_context_data(**kwargs)
hosting_package = self._get_hosting_package()
context.update(
{"hostingpackage": hosting_package, "customer": hosting_package.customer}
)
return context
def form_valid(self, form):
hostingdomain = form.save()
messages.success(
self.request,
_("Successfully created domain {domainname}").format(
domainname=hostingdomain.domain
),
)
return redirect(self._get_hosting_package())

View file

@ -0,0 +1,4 @@
"""
This module contains :py:mod:`fileservertasks.tasks`.
"""

View file

@ -0,0 +1,396 @@
"""
This module defines task stubs for the tasks implemented in the gvafile Celery
worker.
"""
from __future__ import absolute_import
from celery import shared_task
@shared_task
def setup_file_sftp_userdir(username, *args, **kwargs):
"""
This task creates the home directory for an SFTP user if it does not exist
yet.
:param str username: the username
:raises Exception: if the SFTP directory of the user cannot be created
:return: a dictionary with the key :py:const:`username` set to the
username value and a new key :py:const:`sftp_directory` set to the
path of the created SFTP directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.setup_file_sftp_userdir_chained`
at other positions in the task chain.
"""
@shared_task
def setup_file_sftp_userdir_chained(previous_result, *args, **kwargs):
"""
This task creates the home directory for an SFTP user if it does not exist
yet.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` key
:raises Exception: if the SFTP directory of the user cannot be created
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`sftp_directory` key set to the path of the created SFTP
directory
:rtype: dict
"""
@shared_task
def delete_file_sftp_userdir(username, *args, **kwargs):
"""
This task recursively deletes the home directory of an SFTP user if it
exists.
:param str username: the username
:raises Exception: if the SFTP directory of the user cannot be removed
:return: a dictionary with the key :py:const:`username` set to the username
value and the new key :py:const:`sftp_directory` set to the path of the
deleted SFTP directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.delete_file_sftp_userdir_chained`
at other positions in the task chain.
"""
@shared_task
def delete_file_sftp_userdir_chained(previous_result, *args, **kwargs):
"""
This task recursively deletes the home directory of an SFTP user if it
exists.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` key
:raises Exception: if the SFTP directory of the user cannot be removed
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`sftp_directory` key set to the path of the removed SFTP
directory
:rtype: dict
"""
@shared_task
def setup_file_mail_userdir(username, *args, **kwargs):
"""
This task creates the mail base directory for a user if it does not exist
yet.
:param str username: the username
:raises Exception: if the mail base directory for the user cannot be
created
:return: a dictionary with the key :py:const:`username` set to the
username value and a new key :py:const:`mail_directory` set to the path
of the created mail directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.setup_file_mail_userdir_chained`
at other positions in the task chain.
"""
@shared_task
def setup_file_mail_userdir_chained(previous_result, *args, **kwargs):
"""
This task creates the mail base directory for a user if it does not exist
yet.
:param dict previous_result: a dictionary containing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` key
:raises Exception: if the mail base directory for the user cannot be
created
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`mail_directory` key set to the path of the created mail
directory
:rtype: dict
"""
@shared_task
def delete_file_mail_userdir(username, *args, **kwargs):
"""
This task recursively deletes the mail base directory for a user if it
does not exist yet.
:param str username: the username
:raises Exception: if the mail base directory of the user cannot be deleted
:return: a dictionary with the key :py:const:`username` set to the
username value and a new key :py:const:`mail_directory` set to the path
of the deleted mail directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.delete_file_mail_userdir_chained`
at other positions in the task chain.
"""
@shared_task
def delete_file_mail_userdir_chained(previous_result, *args, **kwargs):
"""
This task recursively deletes the mail base directory for a user if it
does not exist yet.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` key
:raises Exception: if the mail base directory of the user cannot be deleted
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`mail_directory` key set to the path of the deleted mail
directory
:rtype: str
"""
@shared_task
def create_file_mailbox(username, mailboxname, *args, **kwargs):
"""
This task creates a new mailbox directory for the given user and mailbox
name.
:param str username: the username
:param str mailboxname: the mailbox name
:raises Exception: if the mailbox directory cannot be created
:return: a dictionary with the keys :py:const:`username` and
:py:const:`mailboxname` set to the values of username and mailboxname
and a new key :py:const:`mailbox_directory` set to the path of the
created mailbox directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.create_file_mailbox_chained` at
other positions in the task chain.
"""
@shared_task
def create_file_mailbox_chained(previous_result, *args, **kwargs):
"""
This task creates a new mailbox directory for the given user and mailbox
name.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` and a :py:const:`mailboxname` key
:raises Exception: if the mailbox directory cannot be created
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`mailbox_directory` key set to the path of the created
mailbox directory
:rtype: dict
"""
@shared_task
def delete_file_mailbox(username, mailboxname, *args, **kwargs):
"""
This task deletes the given mailbox of the given user.
:param str username: the username
:param str mailboxname: the mailbox name
:raises Exception: if the mailbox directory cannot be deleted
:return: a dictionary with the keys :py:const:`username` and
:py:const:`mailboxname` set to the values of username and mailboxname
and a new key :py:const:`mailbox_directory` set to the path of the
deleted mailbox directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use :py:func:`fileservertasks.tasks.delete_file_mailbox_chained` for
other positions in the task chain.
"""
@shared_task
def delete_file_mailbox_chained(previous_result, *args, **kwargs):
"""
This task deletes the given mailbox of the given user.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` and a :py:const:`mailboxname` key
:raises Exception: if the mailbox directory cannot be deleted
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`mailbox_directory` key set to the path of the deleted
mailbox directory
:rtype: dict
"""
@shared_task
def create_file_website_hierarchy(username, sitename, *args, **kwargs):
"""
This task creates the directory hierarchy for a website.
:param str username: the username
:param str sitename: the sitename
:raises Exception: if the website directory hierarchy directory cannot be
created
:return: a dictionary with the keys :py:const:`username` and
:py:const:`sitename` set to the values of username and sitename and a
new key :py:const:`website_directory` set to the path of the created
website directory
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use
:py:func:`fileservertasks.tasks.create_file_website_hierarchy_chained`
at other positions in the task chain
"""
@shared_task
def create_file_website_hierarchy_chained(previous_result, *args, **kwargs):
"""
This task creates the directory hierarchy for a website.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` and a :py:const:`sitename` key
:raises Exception: if the website directory hierarchy directory cannot be
created
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`website_directory` key set to the path of the created
website directory
:rtype: dict
"""
@shared_task
def delete_file_website_hierarchy(username, sitename, *args, **kwargs):
"""
This task deletes a website hierarchy recursively.
:param str username: a username
:param str sitename: a site name
:return: a dictionary with the keys :py:const:`username` and
:py:const:`sitename` set to their original values and a new key
:py:const:`website_directory` set to the path of the deleted website
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use
:py:func:`fileservertasks.tasks.delete_file_website_hierarchy_chained`
at other positions in the task chain
"""
@shared_task
def delete_file_website_hierarchy_chained(previous_result, *args, **kwargs):
"""
This task deletes the website hierarchy recursively.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` and a :py:const:`sitename` key
:raises Exception: if the website directory hierarchy directory cannot be
deleted
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`website_directory` set to the path of the deleted website
directory
:rtype: dict
"""
@shared_task
def set_file_ssh_authorized_keys(username, ssh_keys, *args, **kwargs):
"""
This task set the authorized keys for ssh logins.
:param str username: a username
:param list ssh_keys: a list of ssh keys
:raises Exception: if the update of the creation or update of ssh
authorized_keys failed
:return: a dictionary with the keys :py:const:`username` and
:py:const:`ssh_keys` set to their original values and a new key
:py:const:`ssh_authorized_keys` set to the path of the SSH
authorized_keys file
:rtype: dict
.. note::
This variant can only be used at the beginning of a Celery task chain
or as a standalone task.
Use
:py:func:`fileservertasks.tasks.set_file_ssh_authorized_keys_chained`
at other positions in the task chain
"""
@shared_task
def set_file_ssh_authorized_keys_chained(previous_result, *args, **kwargs):
"""
This task sets the authorized keys for ssh logins.
:param dict previous_result: a dictionary describing the result of the
previous step in the Celery task chain. This dictionary must contain a
:py:const:`username` and a :py:const:`ssh_keys` key
:raises Exception: if the update of the creation or update of ssh
authorized_keys failed
:return: a copy of the :py:obj:`previous_result` dictionary with a new
:py:const:`ssh_authorized_keys` set to the path of the SSH
authorized_keys file
:rtype: dict
"""

View file

@ -1 +1,4 @@
from gnuviechadmin.celery import app as celery_app
# import celery_app to initialize it
from gnuviechadmin.celery import app as celery_app # NOQA
__version__ = "0.15.1"

View file

@ -0,0 +1,11 @@
from allauth.account.adapter import DefaultAccountAdapter
class NoNewUsersAccountAdapter(DefaultAccountAdapter):
"""
Adapter to disable allauth new signups
"""
def is_open_for_signup(self, request):
return False

View file

@ -6,11 +6,15 @@ from celery import Celery
from django.conf import settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'gnuviechadmin.settings.production')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gnuviechadmin.settings")
app = Celery('gnuviechadmin')
app = Celery("gnuviechadmin")
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
def get_installed_apps():
return settings.INSTALLED_APPS
app.config_from_object("django.conf:settings")
app.autodiscover_tasks(get_installed_apps)

View file

@ -0,0 +1,73 @@
"""
This module provides context processor implementations for gnuviechadmin.
"""
from __future__ import absolute_import
import logging
from django.conf import settings
from gnuviechadmin import __version__ as gvaversion
_LOGGER = logging.getLogger(__name__)
def navigation(request):
"""
Add navigation items to the request context.
:param request: Django :py:class:`HttpRequest <django.http.HttpRequest>`
:return: new context items
:rtype: dict
"""
if request.headers.get("x-requested-with") == "XMLHttpRequest":
return {}
context = {
"webmail_url": settings.GVA_LINK_WEBMAIL,
"phpmyadmin_url": settings.GVA_LINK_PHPMYADMIN,
"phppgadmin_url": settings.GVA_LINK_PHPPGADMIN,
"active_item": "dashboard",
}
if request.resolver_match:
viewfunc = request.resolver_match.func
viewmodule = viewfunc.__module__
if viewmodule == "contact_form.views":
context["active_item"] = "contact"
elif viewmodule in (
"hostingpackages.views",
"osusers.views",
"userdbs.views",
"managemails.views",
"websites.views",
"domains.views",
):
context["active_item"] = "hostingpackage"
elif viewmodule in ("allauth.account.views", "allauth.socialaccount.views"):
context["active_item"] = "account"
elif viewmodule == "django.contrib.flatpages.views" and request.path.endswith(
"/impressum/"
):
context["active_item"] = "imprint"
elif not viewmodule.startswith("django.contrib.admin"):
_LOGGER.debug(
"no special handling for view %s in module %s, fallback to "
"default active menu item %s",
viewfunc.__name__,
viewmodule,
context["active_item"],
)
return context
def version_info(request):
"""
Context processor that adds the gnuviechadmin version to the request
context.
"""
context = {
"gnuviechadmin_version": gvaversion,
}
return context

View file

@ -0,0 +1,514 @@
# -*- python -*-
# pymode:lint_ignore=E501
"""
Common settings and globals.
"""
from os.path import abspath, basename, dirname, join, normpath
from django.contrib.messages import constants as messages
from gvacommon.settings_utils import get_env_variable
# ######### PATH CONFIGURATION
# Absolute filesystem path to the Django project directory:
DJANGO_ROOT = dirname(dirname(abspath(__file__)))
# Absolute filesystem path to the top-level project folder:
SITE_ROOT = dirname(DJANGO_ROOT)
# Site name:
SITE_NAME = basename(DJANGO_ROOT)
# ######### END PATH CONFIGURATION
GVA_ENVIRONMENT = get_env_variable("GVA_ENVIRONMENT", default="prod")
# ######### DEBUG CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
DEBUG = GVA_ENVIRONMENT == "local"
# ######### END DEBUG CONFIGURATION
# ######### MANAGER CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#admins
ADMINS = (
(
get_env_variable("GVA_ADMIN_NAME", default="Admin"),
get_env_variable("GVA_ADMIN_EMAIL", default="admin@example.org"),
),
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#managers
MANAGERS = ADMINS
# ######### END MANAGER CONFIGURATION
# ######### DATABASE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": get_env_variable("GVA_PGSQL_DATABASE", default="gnuviechadmin"),
"USER": get_env_variable("GVA_PGSQL_USER", default="gnuviechadmin"),
"PASSWORD": get_env_variable("GVA_PGSQL_PASSWORD"),
"HOST": get_env_variable("GVA_PGSQL_HOSTNAME", default="db"),
"PORT": get_env_variable("GVA_PGSQL_PORT", int, default=5432),
}
}
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
# ######### END DATABASE CONFIGURATION
# ######### GENERAL CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#time-zone
TIME_ZONE = "Europe/Berlin"
# See: https://docs.djangoproject.com/en/dev/ref/settings/#language-code
LANGUAGE_CODE = "en-us"
# See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id
SITE_ID = 1
SITES_DOMAIN_NAME = get_env_variable("GVA_DOMAIN_NAME")
SITES_SITE_NAME = get_env_variable("GVA_SITE_NAME")
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
USE_I18N = True
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
USE_TZ = True
# ######### END GENERAL CONFIGURATION
LOCALE_PATHS = (normpath(join(SITE_ROOT, "gnuviechadmin", "locale")),)
# ######### MEDIA CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root
MEDIA_ROOT = normpath(join(SITE_ROOT, "media"))
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url
MEDIA_URL = "/media/"
# ######### END MEDIA CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
STATIC_URL = "/static/"
# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS # noqa
STATICFILES_DIRS = (normpath(join(SITE_ROOT, "gnuviechadmin", "static")),)
# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders # noqa
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
)
# ######### END STATIC FILE CONFIGURATION
# ######### SECRET CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# Note: This key should only be used for development and testing.
SECRET_KEY = get_env_variable("GVA_SITE_SECRET")
# ######### END SECRET CONFIGURATION
# ######### SITE CONFIGURATION
# Hosts/domain names that are valid for this site
# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
ALLOWED_HOSTS = []
# ######### END SITE CONFIGURATION
# ######### FIXTURE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FIXTURE_DIRS # noqa
FIXTURE_DIRS = (normpath(join(SITE_ROOT, "fixtures")),)
# ######### END FIXTURE CONFIGURATION
# ######### TEMPLATE CONFIGURATION
# See: https://docs.djangoproject.com/en/1.9/ref/settings/#std:setting-TEMPLATES # noqa
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [normpath(join(DJANGO_ROOT, "templates"))],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.contrib.auth.context_processors.auth",
"django.template.context_processors.debug",
"django.template.context_processors.i18n",
"django.template.context_processors.media",
"django.template.context_processors.static",
"django.template.context_processors.tz",
"django.contrib.messages.context_processors.messages",
"django.template.context_processors.request",
# custom context processors
"gnuviechadmin.context_processors.navigation",
"gnuviechadmin.context_processors.version_info",
]
},
}
]
# ######### END TEMPLATE CONFIGURATION
# ######### MIDDLEWARE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#middleware-classes
MIDDLEWARE = [
# Default Django middleware.
"django.middleware.common.CommonMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"allauth.account.middleware.AccountMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
# uncomment next line to enable translation to browser locale
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
# ######### END MIDDLEWARE CONFIGURATION
AUTHENTICATION_BACKENDS = (
# Needed to login by username in Django admin, regardless of `allauth`
"django.contrib.auth.backends.ModelBackend",
# `allauth` specific authentication methods, such as login by e-mail
"allauth.account.auth_backends.AuthenticationBackend",
)
# ######### URL CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf
ROOT_URLCONF = "%s.urls" % SITE_NAME
# ######### END URL CONFIGURATION
# ######### TEST RUNNER CONFIGURATION
TEST_RUNNER = "django.test.runner.DiscoverRunner"
# ######### END TEST RUNNER CONFIGURATION
# ######### APP CONFIGURATION
DJANGO_APPS = (
# Default Django apps:
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.sites",
"django.contrib.messages",
"django.contrib.staticfiles",
# Useful template tags:
"django.contrib.humanize",
# Admin panel and documentation:
"django.contrib.admin",
# Flatpages for about page
"django.contrib.flatpages",
"crispy_forms",
"crispy_bootstrap5",
"impersonate",
"rest_framework",
"rest_framework.authtoken",
)
ALLAUTH_APPS = (
"allauth",
"allauth.account",
"allauth.socialaccount",
"allauth.socialaccount.providers.google",
"allauth.socialaccount.providers.linkedin_oauth2",
)
# Apps specific for this project go here.
LOCAL_APPS = (
"dashboard",
"taskresults",
"ldaptasks",
"mysqltasks",
"pgsqltasks",
"fileservertasks",
"webtasks",
"domains",
"osusers",
"managemails",
"userdbs",
"hostingpackages",
"websites",
"help",
"invoices",
"contact_form",
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + ALLAUTH_APPS + LOCAL_APPS
MESSAGE_TAGS = {
messages.DEBUG: "",
messages.ERROR: "alert-danger",
messages.INFO: "alert-info",
messages.SUCCESS: "alert-success",
messages.WARNING: "alert-warning",
}
# ######### END APP CONFIGURATION
# ######### ALLAUTH CONFIGURATION
ACCOUNT_ADAPTER = "gnuviechadmin.auth.NoNewUsersAccountAdapter"
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
LOGIN_REDIRECT_URL = "/"
SOCIALACCOUNT_AUTO_SIGNUP = False
SOCIALACCOUNT_QUERY_EMAIL = True
# ######### END ALLAUTH CONFIGURATION
# ######### CRISPY FORMS CONFIGURATION
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
# ######### END CRISPY_FORMS CONFIGURATION
# ######### REST FRAMEWORK CONFIGURATION
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.BasicAuthentication",
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication",
],
"DEFAULT_RENDERER_CLASSES": [
"rest_framework.renderers.JSONRenderer",
],
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAdminUser",
],
}
# ######### END REST FRAMEWORK CONFIGURATION
# ######### LOGGING CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#logging
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"verbose": {
"format": "%(levelname)s %(asctime)s %(name)s "
"%(module)s:%(lineno)d %(process)d %(thread)d %(message)s"
},
"simple": {"format": "%(levelname)s %(name)s:%(lineno)d %(message)s"},
},
"filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}},
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
"logfile": {
"level": "INFO",
"class": "logging.FileHandler",
"filename": get_env_variable("GVA_LOG_FILE", default="gva.log"),
"formatter": "verbose",
},
"mail_admins": {
"level": "ERROR",
"filters": ["require_debug_false"],
"class": "django.utils.log.AdminEmailHandler",
},
},
"root": {
"handlers": ["console"],
"level": "WARNING",
},
"loggers": {
"django.request": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": True,
},
"django": {
"handlers": ["logfile"],
"level": "INFO",
"propagate": False,
},
},
}
for app in LOCAL_APPS:
LOGGING["loggers"][app] = {
"handlers": ["logfile"],
"level": "INFO",
"propagate": False,
}
# ######### END LOGGING CONFIGURATION
# ######### WSGI CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
WSGI_APPLICATION = "%s.wsgi.application" % SITE_NAME
# ######### END WSGI CONFIGURATION
# ######### CELERY CONFIGURATION
BROKER_URL = get_env_variable(
"GVA_BROKER_URL", default="amqp://gnuviechadmin:gnuviechadmin@mq/gnuviechadmin"
)
BROKER_TRANSPORT_OPTIONS = {
"max_retries": 3,
"interval_start": 0,
"interval_step": 0.2,
"interval_max": 0.2,
}
CELERY_RESULT_BACKEND = get_env_variable(
"GVA_RESULTS_REDIS_URL", default="redis://:gnuviechadmin@redis:6379/0"
)
CELERY_TASK_RESULT_EXPIRES = None
CELERY_ROUTES = ("gvacommon.celeryrouters.GvaRouter",)
CELERY_TIMEZONE = "Europe/Berlin"
CELERY_ENABLE_UTC = True
CELERY_ACCEPT_CONTENT = ["json"]
CELERY_TASK_SERIALIZER = "json"
CELERY_RESULT_SERIALIZER = "json"
# ######### END CELERY CONFIGURATION
# ######### CUSTOM APP CONFIGURATION
OSUSER_MINUID = get_env_variable("GVA_MIN_OS_UID", int, default=10000)
OSUSER_MINGID = get_env_variable("GVA_MIN_OS_GID", int, default=10000)
OSUSER_USERNAME_PREFIX = get_env_variable("GVA_OSUSER_PREFIX", default="usr")
OSUSER_HOME_BASEPATH = get_env_variable("GVA_OSUSER_HOME_BASEPATH", default="/home")
OSUSER_DEFAULT_SHELL = get_env_variable(
"GVA_OSUSER_DEFAULT_SHELL", default="/usr/bin/rssh"
)
OSUSER_SFTP_GROUP = "sftponly"
OSUSER_SSH_GROUP = "sshusers"
OSUSER_DEFAULT_GROUPS = [OSUSER_SFTP_GROUP]
OSUSER_UPLOAD_SERVER = get_env_variable("GVA_OSUSER_UPLOADSERVER", default="file")
GVA_LINK_WEBMAIL = get_env_variable(
"GVA_WEBMAIL_URL", default="https://webmail.example.org/"
)
GVA_LINK_PHPMYADMIN = get_env_variable(
"GVA_PHPMYADMIN_URL", default="https://phpmyadmin.example.org/"
)
GVA_LINK_PHPPGADMIN = get_env_variable(
"GVA_PHPPGADMIN_URL", default="https://phppgadmin.example.org/"
)
# ######### END CUSTOM APP CONFIGURATION
# ######### STATIC FILE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root
STATIC_ROOT = "/srv/gva/static/"
def show_debug_toolbar(request):
return DEBUG and GVA_ENVIRONMENT == "local"
# ######### TOOLBAR CONFIGURATION
# See: http://django-debug-toolbar.readthedocs.org/en/latest/installation.html#explicit-setup # noqa
INSTALLED_APPS += ("debug_toolbar",)
MIDDLEWARE += [
"impersonate.middleware.ImpersonateMiddleware",
"debug_toolbar.middleware.DebugToolbarMiddleware",
]
DEBUG_TOOLBAR_CONFIG = {
"SHOW_TOOLBAR_CALLBACK": "gnuviechadmin.settings.show_debug_toolbar"
}
# ######### END TOOLBAR CONFIGURATION
if GVA_ENVIRONMENT == "local":
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
TEMPLATES[0]["OPTIONS"]["debug"] = DEBUG
# ######### END DEBUG CONFIGURATION
# ######### EMAIL CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
# ######### END EMAIL CONFIGURATION
# ######### CACHE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#caches
CACHES = {"default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}}
# ######### END CACHE CONFIGURATION
LOGGING["handlers"].update(
{
"console": {
"level": "DEBUG",
"class": "logging.StreamHandler",
"formatter": "simple",
}
}
)
LOGGING["loggers"].update(
dict(
[
(key, {"handlers": ["console"], "level": "DEBUG", "propagate": True})
for key in LOCAL_APPS
],
)
)
elif GVA_ENVIRONMENT == "test":
ALLOWED_HOSTS = ["localhost"]
PASSWORD_HASHERS = ("django.contrib.auth.hashers.MD5PasswordHasher",)
LOGGING["handlers"].update(
{
"console": {
"level": "ERROR",
"class": "logging.StreamHandler",
"formatter": "simple",
}
}
)
LOGGING["loggers"].update(
dict(
[
(key, {"handlers": ["console"], "level": "ERROR", "propagate": True})
for key in LOCAL_APPS
]
)
)
LOGGING["loggers"]["django"] = {
"handlers": ["console"],
"level": "CRITICAL",
"propagate": True,
}
BROKER_URL = BROKER_URL + "_test"
CELERY_RESULT_PERSISTENT = False
else:
# ######### HOST CONFIGURATION
# See: https://docs.djangoproject.com/en/1.5/releases/1.5/#allowed-hosts-required-in-production # noqa
ALLOWED_HOSTS = [SITES_DOMAIN_NAME]
# ######### END HOST CONFIGURATION
# ######### EMAIL CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
EMAIL_SUBJECT_PREFIX = "[%s] " % SITE_NAME
# See: https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email
DEFAULT_FROM_EMAIL = get_env_variable(
"GVA_SITE_ADMINMAIL", default="admin@example.org"
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#server-email
SERVER_EMAIL = get_env_variable("GVA_SITE_ADMINMAIL", default="admin@example.org")
# ######### END EMAIL CONFIGURATION
# ######### CACHE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#caches
# CACHES = {}
# ######### END CACHE CONFIGURATION
# ######### ALLAUTH PRODUCTION CONFIGURATION
ACCOUNT_EMAIL_SUBJECT_PREFIX = "[Jan Dittberner IT-Consulting & -Solutions] "
ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https"
# ######### END ALLAUTH PRODUCTION CONFIGURATION

View file

@ -1,302 +0,0 @@
# -*- python -*-
# pymode:lint_ignore=E501
"""Common settings and globals."""
from os import environ
from os.path import abspath, basename, dirname, join, normpath
from sys import path
# Normally you should not import ANYTHING from Django directly
# into your settings, but ImproperlyConfigured is an exception.
from django.core.exceptions import ImproperlyConfigured
def get_env_variable(var_name):
"""
Get a setting from an environment variable.
:param str var_name: variable name
"""
try:
return environ[var_name]
except KeyError:
error_msg = "Set the %s environment variable" % var_name
raise ImproperlyConfigured(error_msg)
########## PATH CONFIGURATION
# Absolute filesystem path to the Django project directory:
DJANGO_ROOT = dirname(dirname(abspath(__file__)))
# Absolute filesystem path to the top-level project folder:
SITE_ROOT = dirname(DJANGO_ROOT)
# Site name:
SITE_NAME = basename(DJANGO_ROOT)
# Add our project to our pythonpath, this way we don't need to type our project
# name in our dotted import paths:
path.append(DJANGO_ROOT)
########## END PATH CONFIGURATION
########## DEBUG CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
DEBUG = False
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
TEMPLATE_DEBUG = DEBUG
########## END DEBUG CONFIGURATION
########## MANAGER CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#admins
ADMINS = (
(get_env_variable('GVA_ADMIN_NAME'), get_env_variable('GVA_ADMIN_EMAIL')),
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#managers
MANAGERS = ADMINS
########## END MANAGER CONFIGURATION
########## DATABASE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': get_env_variable('GVA_PGSQL_DATABASE'),
'USER': get_env_variable('GVA_PGSQL_USER'),
'PASSWORD': get_env_variable('GVA_PGSQL_PASSWORD'),
'HOST': get_env_variable('GVA_PGSQL_HOSTNAME'),
'PORT': get_env_variable('GVA_PGSQL_PORT'),
}
}
########## END DATABASE CONFIGURATION
########## GENERAL CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#time-zone
TIME_ZONE = 'Europe/Berlin'
# See: https://docs.djangoproject.com/en/dev/ref/settings/#language-code
LANGUAGE_CODE = 'en-us'
# See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id
SITE_ID = 1
SITES_DOMAIN_NAME = get_env_variable('GVA_DOMAIN_NAME')
SITES_SITE_NAME = get_env_variable('GVA_SITE_NAME')
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
USE_I18N = True
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n
USE_L10N = True
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
USE_TZ = True
########## END GENERAL CONFIGURATION
########## MEDIA CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root
MEDIA_ROOT = normpath(join(SITE_ROOT, 'media'))
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url
MEDIA_URL = '/media/'
########## END MEDIA CONFIGURATION
########## STATIC FILE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root
STATIC_ROOT = normpath(join(SITE_ROOT, 'assets'))
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
STATIC_URL = '/static/'
# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
STATICFILES_DIRS = (
normpath(join(SITE_ROOT, 'static')),
)
# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
########## END STATIC FILE CONFIGURATION
########## SECRET CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
# Note: This key should only be used for development and testing.
SECRET_KEY = get_env_variable('GVA_SITE_SECRET')
########## END SECRET CONFIGURATION
########## SITE CONFIGURATION
# Hosts/domain names that are valid for this site
# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
ALLOWED_HOSTS = []
########## END SITE CONFIGURATION
########## FIXTURE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FIXTURE_DIRS
FIXTURE_DIRS = (
normpath(join(SITE_ROOT, 'fixtures')),
)
########## END FIXTURE CONFIGURATION
########## TEMPLATE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'django.core.context_processors.request',
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
TEMPLATE_DIRS = (
normpath(join(SITE_ROOT, 'templates')),
)
########## END TEMPLATE CONFIGURATION
########## MIDDLEWARE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#middleware-classes
MIDDLEWARE_CLASSES = (
# Default Django middleware.
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# uncomment next line to enable translation to browser locale
'django.middleware.locale.LocaleMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
########## END MIDDLEWARE CONFIGURATION
########## URL CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf
ROOT_URLCONF = '%s.urls' % SITE_NAME
########## END URL CONFIGURATION
########## TEST RUNNER CONFIGURATION
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
########## END TEST RUNNER CONFIGURATION
########## APP CONFIGURATION
DJANGO_APPS = (
# Default Django apps:
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Useful template tags:
'django.contrib.humanize',
# Admin panel and documentation:
'django.contrib.admin',
# 'django.contrib.admindocs',
)
# Apps specific for this project go here.
LOCAL_APPS = (
'taskresults',
'mysqltasks',
'pgsqltasks',
'domains',
'osusers',
'managemails',
'userdbs',
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + LOCAL_APPS
########## END APP CONFIGURATION
########## LOGGING CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#logging
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
########## END LOGGING CONFIGURATION
########## WSGI CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
WSGI_APPLICATION = '%s.wsgi.application' % SITE_NAME
########## END WSGI CONFIGURATION
########## CELERY CONFIGURATION
BROKER_URL = get_env_variable('GVA_BROKER_URL')
CELERY_RESULT_BACKEND = 'amqp'
CELERY_RESULT_PERSISTENT = True
CELERY_TASK_RESULT_EXPIRES = None
CELERY_ROUTES = (
'gvacommon.celeryrouters.GvaRouter',
)
CELERY_TIMEZONE = 'Europe/Berlin'
CELERY_ENABLE_UTC = True
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
########## END CELERY CONFIGURATION
########## CUSTOM APP CONFIGURATION
OSUSER_MINUID = int(get_env_variable('GVA_MIN_OS_UID'))
OSUSER_MINGID = int(get_env_variable('GVA_MIN_OS_GID'))
OSUSER_USERNAME_PREFIX = get_env_variable('GVA_OSUSER_PREFIX')
OSUSER_HOME_BASEPATH = get_env_variable('GVA_OSUSER_HOME_BASEPATH')
OSUSER_DEFAULT_SHELL = get_env_variable('GVA_OSUSER_DEFAULT_SHELL')
########## END CUSTOM APP CONFIGURATION

View file

@ -1,49 +0,0 @@
# -*- python -*-
# pymode:lint_ignore=W0401,E501
"""Development settings and globals."""
from __future__ import absolute_import
from .base import *
########## DEBUG CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
DEBUG = True
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
TEMPLATE_DEBUG = DEBUG
########## END DEBUG CONFIGURATION
########## EMAIL CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
########## END EMAIL CONFIGURATION
########## CACHE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#caches
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
}
}
########## END CACHE CONFIGURATION
########## TOOLBAR CONFIGURATION
# See: http://django-debug-toolbar.readthedocs.org/en/latest/installation.html#explicit-setup
INSTALLED_APPS += (
'debug_toolbar',
)
MIDDLEWARE_CLASSES += (
'debug_toolbar.middleware.DebugToolbarMiddleware',
)
DEBUG_TOOLBAR_PATCH_SETTINGS = False
# http://django-debug-toolbar.readthedocs.org/en/latest/installation.html
INTERNAL_IPS = ('127.0.0.1', '10.0.2.2')
########## END TOOLBAR CONFIGURATION

View file

@ -1,28 +0,0 @@
# -*- python -*-
# pymode:lint_ignore=W0401,E501
"""Production settings and globals."""
from __future__ import absolute_import
from .base import *
########## HOST CONFIGURATION
# See: https://docs.djangoproject.com/en/1.5/releases/1.5/#allowed-hosts-required-in-production
ALLOWED_HOSTS = [SITES_DOMAIN_NAME]
########## END HOST CONFIGURATION
########## EMAIL CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
EMAIL_SUBJECT_PREFIX = '[%s] ' % SITE_NAME
# See: https://docs.djangoproject.com/en/dev/ref/settings/#server-email
SERVER_EMAIL = get_env_variable('GVA_SITE_ADMINMAIL')
########## END EMAIL CONFIGURATION
########## CACHE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#caches
#CACHES = {}
########## END CACHE CONFIGURATION

View file

@ -1,3 +0,0 @@
from __future__ import absolute_import
from .base import *

View file

@ -1,28 +0,0 @@
import os
from unittest import TestCase
from django.core.exceptions import ImproperlyConfigured
from gnuviechadmin.settings.base import get_env_variable
class GetEnvVariableTest(TestCase):
def test_get_existing_env_variable(self):
os.environ['testvariable'] = 'myvalue'
self.assertEqual(get_env_variable('testvariable'), 'myvalue')
def test_get_missing_env_variable(self):
if 'missingvariable' in os.environ:
del os.environ['missingvariable']
with self.assertRaises(ImproperlyConfigured) as e:
get_env_variable('missingvariable')
self.assertEqual(
str(e.exception), 'Set the missingvariable environment variable')
class WSGITest(TestCase):
def test_wsgi_application(self):
from gnuviechadmin import wsgi
self.assertIsNotNone(wsgi.application)

View file

@ -0,0 +1,2 @@
# -*- python -*-
# -*- coding: utf-8 -*-

View file

@ -0,0 +1,10 @@
from unittest import TestCase
from gnuviechadmin.celery import get_installed_apps
from django.conf import settings
class GetInstalledAppsTest(TestCase):
def test_get_installed_apps(self):
self.assertEqual(get_installed_apps(), settings.INSTALLED_APPS)

View file

@ -0,0 +1,111 @@
# -*- python -*-
# -*- coding: utf-8 -*-
"""
This module contains tests for :py:mod:`gnuviechadmin.context_processors`.
"""
from unittest.mock import MagicMock
from django.conf import settings
from django.contrib.auth import get_user_model
from django.http import HttpRequest
from django.test import TestCase
from django.urls import reverse
from gnuviechadmin import __version__ as gvaversion
from gnuviechadmin.context_processors import navigation
User = get_user_model()
TEST_USER = "test"
TEST_PASSWORD = "secret"
class NavigationContextProcessorTest(TestCase):
EXPECTED_ITEMS = ("webmail_url", "phpmyadmin_url", "phppgadmin_url", "active_item")
def test_ajax_request(self):
response = self.client.get("/accounts/login/", HTTP_X_REQUESTED_WITH="XMLHttpRequest")
for item in self.EXPECTED_ITEMS:
self.assertNotIn(item, response.context)
def _check_static_urls(self, context):
self.assertEqual(context["webmail_url"], settings.GVA_LINK_WEBMAIL)
self.assertEqual(context["phpmyadmin_url"], settings.GVA_LINK_PHPMYADMIN)
self.assertEqual(context["phppgadmin_url"], settings.GVA_LINK_PHPPGADMIN)
def test_index_page_context(self):
user = User.objects.create(username=TEST_USER)
user.set_password(TEST_PASSWORD)
user.save()
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
response = self.client.get("/")
for item in self.EXPECTED_ITEMS:
self.assertIn(item, response.context)
self._check_static_urls(response.context)
self.assertEqual(response.context["active_item"], "dashboard")
def test_contact_page_context(self):
response = self.client.get(reverse("contact_form"))
for item in self.EXPECTED_ITEMS:
self.assertIn(item, response.context)
self._check_static_urls(response.context)
self.assertEqual(response.context["active_item"], "contact")
def _test_page_context_by_viewmodule(self, viewmodule, expecteditem):
request = HttpRequest()
request.resolver_match = MagicMock()
request.resolver_match.func.__module__ = viewmodule
context = navigation(request)
for item in self.EXPECTED_ITEMS:
self.assertIn(item, context)
self._check_static_urls(context)
self.assertEqual(context["active_item"], expecteditem)
def test_osusers_page_context(self):
self._test_page_context_by_viewmodule("osusers.views", "hostingpackage")
def test_userdbs_page_context(self):
self._test_page_context_by_viewmodule("userdbs.views", "hostingpackage")
def test_managemails_page_context(self):
self._test_page_context_by_viewmodule("managemails.views", "hostingpackage")
def test_websites_page_context(self):
self._test_page_context_by_viewmodule("websites.views", "hostingpackage")
def test_domains_page_context(self):
self._test_page_context_by_viewmodule("domains.views", "hostingpackage")
def test_allauth_account_page_context(self):
self._test_page_context_by_viewmodule("allauth.account.views", "account")
def test_allauth_socialaccount_page_context(self):
self._test_page_context_by_viewmodule("allauth.socialaccount.views", "account")
def test_imprint_page_context(self):
response = self.client.get(reverse("imprint"))
for item in self.EXPECTED_ITEMS:
self.assertIn(item, response.context)
self._check_static_urls(response.context)
self.assertEqual(response.context["active_item"], "imprint")
def test_no_resolver_match(self):
request = HttpRequest()
context = navigation(request)
self._check_static_urls(context)
self.assertEqual(context["active_item"], "dashboard")
def test_admin_module(self):
self._test_page_context_by_viewmodule("django.contrib.admin.foo", "dashboard")
class VersionInfoContextProcessorTest(TestCase):
def test_version_info_in_context(self):
response = self.client.get("/accounts/login/")
self.assertIn("gnuviechadmin_version", response.context)
self.assertEqual(response.context["gnuviechadmin_version"], gvaversion)

View file

@ -0,0 +1,10 @@
# -*- python -*-
# -*- coding: utf-8 -*-
from unittest import TestCase
class WSGITest(TestCase):
def test_wsgi_application(self):
from gnuviechadmin import wsgi
self.assertIsNotNone(wsgi.application)

Some files were not shown because too many files have changed in this diff Show more