Merge branch 'drop_photologue' into 'master'
Drop photologue dependency Closes #12 See merge request bde/photo21!21
This commit is contained in:
commit
5fc7ea11b0
47 changed files with 3415 additions and 197 deletions
13
README.md
13
README.md
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
Le serveur photos est un projet Django permettant de gérer les photos de la vie
|
||||
associative de l'ENS Paris-Saclay.
|
||||
|
||||
## Table des matières
|
||||
|
||||
- [Installation d'une instance de développement](#installation-dune-instance-de-développement)
|
||||
|
|
@ -44,14 +47,16 @@ Bien que cela permette de créer une instance sur toutes les distributions,
|
|||
Pour initialiser la base de données avec de quoi travailler.
|
||||
|
||||
```bash
|
||||
(env)$ ./manage.py collectstatic --noinput
|
||||
(env)$ ./manage.py compilemessages
|
||||
(env)$ ./manage.py migrate
|
||||
(env)$ ./manage.py loaddata initial
|
||||
(env)$ ./manage.py createsuperuser # Création d'un utilisateur initial
|
||||
```
|
||||
|
||||
6. Enjoy :
|
||||
6. **Activation du mode déboguage.**
|
||||
Dans `photo21/settings.py`, changer `DEBUG` à `True`.
|
||||
|
||||
7. Enjoy :
|
||||
|
||||
```bash
|
||||
(env)$ ./manage.py runserver 0.0.0.0:8000
|
||||
|
|
@ -63,10 +68,10 @@ de la note sur un téléphone !
|
|||
|
||||
## Installation d'une instance de production
|
||||
|
||||
**En production on souhaite absolument utiliser les modules Python packagées
|
||||
**En production on souhaite utiliser les modules Python packagées
|
||||
dans le gestionnaire de paquet.** Cela permet de mettre à jour facilement les
|
||||
dépendances critiques telles que Django. L'installation d'une instance de
|
||||
production néccessite **une installation de Debian Bullseye**.
|
||||
production néccessite **une installation de Debian Bullseye ou plus récent**.
|
||||
|
||||
1. **Installation des dépendances APT.**
|
||||
On tire les dépendances le plus possible à partir des dépôts de Debian.
|
||||
|
|
|
|||
315
photo21/locale/de/LC_MESSAGES/django.po
Normal file
315
photo21/locale/de/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
# 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.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-01-29 21:58+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: photo21/forms.py:12
|
||||
msgid ""
|
||||
"Please enter a valid email address ending with `@crans.org` or `@ens-paris-"
|
||||
"saclay.fr`."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/forms.py:23
|
||||
msgid "Must end with `@crans.org` or `@ens-paris-saclay.fr`."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/hashers.py:42
|
||||
msgid "algorithm"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/hashers.py:43
|
||||
msgid "salt"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/hashers.py:44
|
||||
msgid "hash"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/settings.py:162
|
||||
msgid "German"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/settings.py:163
|
||||
msgid "English"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/settings.py:164
|
||||
msgid "Spanish"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/settings.py:165
|
||||
msgid "French"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/400.html:10
|
||||
msgid "Bad request"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/400.html:14
|
||||
msgid ""
|
||||
"Sorry, your request was bad. Don't know what could be wrong. An email has "
|
||||
"been sent to webmasters with the details of the error. You can now drink a "
|
||||
"coke."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/403.html:10
|
||||
msgid "Permission denied"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/403.html:13
|
||||
msgid "You don't have the right to perform this request."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/403.html:15 photo21/templates/404.html:19
|
||||
msgid "Exception message:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/404.html:10
|
||||
msgid "Page not found"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/404.html:14
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The requested path <code>%(request_path)s</code> was not found on the server."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/500.html:10
|
||||
msgid "Server error"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/500.html:14
|
||||
msgid ""
|
||||
"Sorry, an error occurred when processing your request. An email has been "
|
||||
"sent to webmasters with the detail of the error, and this will be fixed "
|
||||
"soon. You can now drink a beer."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:6
|
||||
#: photo21/templates/account/email.html:14
|
||||
#: photo21/templates/socialaccount/connections.html:14
|
||||
msgid "E-mail Addresses"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:9 photo21/templates/base.html:59
|
||||
#: photo21/templates/socialaccount/connections.html:9
|
||||
msgid "Account"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:17
|
||||
#: photo21/templates/socialaccount/connections.html:17
|
||||
msgid "Social connections"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:23
|
||||
msgid "The following e-mail addresses are associated with your account:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:34
|
||||
msgid "Verified"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:36
|
||||
msgid "Unverified"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:38
|
||||
msgid "Primary"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:44
|
||||
msgid "Make Primary"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:45
|
||||
msgid "Re-send Verification"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:46
|
||||
#: photo21/templates/socialaccount/connections.html:45
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:51
|
||||
msgid "Warning:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:51
|
||||
msgid ""
|
||||
"You currently do not have any e-mail address set up. You should really add "
|
||||
"an e-mail address so you can receive notifications, reset your password, etc."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:55
|
||||
msgid "Add E-mail Address"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:60
|
||||
msgid "Add E-mail"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:68
|
||||
msgid "Do you really want to remove the selected e-mail address?"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:6
|
||||
#: photo21/templates/account/login.html:11
|
||||
#: photo21/templates/account/login.html:39
|
||||
msgid "Sign In"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:16
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Please sign in with one of your existing third party accounts. Or, <a href="
|
||||
"\"%(signup_url)s\">sign up</a> for a %(site_name)s account and sign in below:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:24
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:30
|
||||
#, python-format
|
||||
msgid ""
|
||||
"If you have not created an account yet, then please <a href=\"%(signup_url)s"
|
||||
"\">sign up</a> first."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:40
|
||||
msgid "Forgot Password?"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:44
|
||||
msgid "If any problem, please contact the server owners at"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/signup.html:6
|
||||
msgid "Signup"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/signup.html:11
|
||||
#: photo21/templates/account/signup.html:22
|
||||
msgid "Sign Up"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/signup.html:14
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Already have an account? Then please <a href=\"%(login_url)s\">sign in</a>."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:12
|
||||
msgid "The ENS Paris-Saclay pictures server."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:37
|
||||
msgid "Galleries"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:42
|
||||
msgid "Upload"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:47
|
||||
msgid "Manage"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:68
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:78
|
||||
msgid "Log in"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:87
|
||||
msgid "Sign up"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:109
|
||||
msgid "Source code"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:6
|
||||
msgid "Home"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:9
|
||||
msgid "Welcome to the pictures server!"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:11
|
||||
msgid ""
|
||||
"This website aims to collect the pictures and movies taken in the student "
|
||||
"life of ENS Paris-Saclay-Saclay or involving its students."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:18
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The pictures are visible in <a href=\"%(gallery_archive_url)s\">the "
|
||||
"galleries</a> and are downloadable. <b>However, the agreement of the "
|
||||
"photographer and the persons present on the photo is necessary before any "
|
||||
"republication on another platform. </b>"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:27
|
||||
msgid ""
|
||||
"If you want a photo to be deleted, please let us know: <a href=\"mailto:"
|
||||
"photos@crans.org?subject=[ABUS] Nouvelle requête\" class=\"btn btn-dark btn-"
|
||||
"sm\">Abuse request</a>"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:33
|
||||
msgid ""
|
||||
"If you want to obtain the right to upload pictures, please let us know: <a "
|
||||
"href=\"mailto:photos@crans.org?subject=[Photographe] Demande de droits "
|
||||
"photographe\" class=\"btn btn-dark btn-sm\">Become a photograph</a>"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:39
|
||||
msgid "Last galleries"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:50
|
||||
msgid "Connected as"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:53
|
||||
msgid "Select another language:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/socialaccount/connections.html:6
|
||||
msgid "Account Connections"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/socialaccount/connections.html:23
|
||||
msgid ""
|
||||
"You can sign in to your account using any of the following third party "
|
||||
"accounts:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/socialaccount/connections.html:51
|
||||
msgid ""
|
||||
"You currently have no social network accounts connected to this account."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/socialaccount/connections.html:54
|
||||
msgid "Add a 3rd Party Account"
|
||||
msgstr ""
|
||||
314
photo21/locale/es/LC_MESSAGES/django.po
Normal file
314
photo21/locale/es/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
# 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.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-01-29 21:58+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: photo21/forms.py:12
|
||||
msgid ""
|
||||
"Please enter a valid email address ending with `@crans.org` or `@ens-paris-"
|
||||
"saclay.fr`."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/forms.py:23
|
||||
msgid "Must end with `@crans.org` or `@ens-paris-saclay.fr`."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/hashers.py:42
|
||||
msgid "algorithm"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/hashers.py:43
|
||||
msgid "salt"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/hashers.py:44
|
||||
msgid "hash"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/settings.py:162
|
||||
msgid "German"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/settings.py:163
|
||||
msgid "English"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/settings.py:164
|
||||
msgid "Spanish"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/settings.py:165
|
||||
msgid "French"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/400.html:10
|
||||
msgid "Bad request"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/400.html:14
|
||||
msgid ""
|
||||
"Sorry, your request was bad. Don't know what could be wrong. An email has "
|
||||
"been sent to webmasters with the details of the error. You can now drink a "
|
||||
"coke."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/403.html:10
|
||||
msgid "Permission denied"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/403.html:13
|
||||
msgid "You don't have the right to perform this request."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/403.html:15 photo21/templates/404.html:19
|
||||
msgid "Exception message:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/404.html:10
|
||||
msgid "Page not found"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/404.html:14
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The requested path <code>%(request_path)s</code> was not found on the server."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/500.html:10
|
||||
msgid "Server error"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/500.html:14
|
||||
msgid ""
|
||||
"Sorry, an error occurred when processing your request. An email has been "
|
||||
"sent to webmasters with the detail of the error, and this will be fixed "
|
||||
"soon. You can now drink a beer."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:6
|
||||
#: photo21/templates/account/email.html:14
|
||||
#: photo21/templates/socialaccount/connections.html:14
|
||||
msgid "E-mail Addresses"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:9 photo21/templates/base.html:59
|
||||
#: photo21/templates/socialaccount/connections.html:9
|
||||
msgid "Account"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:17
|
||||
#: photo21/templates/socialaccount/connections.html:17
|
||||
msgid "Social connections"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:23
|
||||
msgid "The following e-mail addresses are associated with your account:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:34
|
||||
msgid "Verified"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:36
|
||||
msgid "Unverified"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:38
|
||||
msgid "Primary"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:44
|
||||
msgid "Make Primary"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:45
|
||||
msgid "Re-send Verification"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:46
|
||||
#: photo21/templates/socialaccount/connections.html:45
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:51
|
||||
msgid "Warning:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:51
|
||||
msgid ""
|
||||
"You currently do not have any e-mail address set up. You should really add "
|
||||
"an e-mail address so you can receive notifications, reset your password, etc."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:55
|
||||
msgid "Add E-mail Address"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:60
|
||||
msgid "Add E-mail"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:68
|
||||
msgid "Do you really want to remove the selected e-mail address?"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:6
|
||||
#: photo21/templates/account/login.html:11
|
||||
#: photo21/templates/account/login.html:39
|
||||
msgid "Sign In"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:16
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Please sign in with one of your existing third party accounts. Or, <a href="
|
||||
"\"%(signup_url)s\">sign up</a> for a %(site_name)s account and sign in below:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:24
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:30
|
||||
#, python-format
|
||||
msgid ""
|
||||
"If you have not created an account yet, then please <a href=\"%(signup_url)s"
|
||||
"\">sign up</a> first."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:40
|
||||
msgid "Forgot Password?"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/login.html:44
|
||||
msgid "If any problem, please contact the server owners at"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/signup.html:6
|
||||
msgid "Signup"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/signup.html:11
|
||||
#: photo21/templates/account/signup.html:22
|
||||
msgid "Sign Up"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/signup.html:14
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Already have an account? Then please <a href=\"%(login_url)s\">sign in</a>."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:12
|
||||
msgid "The ENS Paris-Saclay pictures server."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:37
|
||||
msgid "Galleries"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:42
|
||||
msgid "Upload"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:47
|
||||
msgid "Manage"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:68
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:78
|
||||
msgid "Log in"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:87
|
||||
msgid "Sign up"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:109
|
||||
msgid "Source code"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:6
|
||||
msgid "Home"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:9
|
||||
msgid "Welcome to the pictures server!"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:11
|
||||
msgid ""
|
||||
"This website aims to collect the pictures and movies taken in the student "
|
||||
"life of ENS Paris-Saclay-Saclay or involving its students."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:18
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The pictures are visible in <a href=\"%(gallery_archive_url)s\">the "
|
||||
"galleries</a> and are downloadable. <b>However, the agreement of the "
|
||||
"photographer and the persons present on the photo is necessary before any "
|
||||
"republication on another platform. </b>"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:27
|
||||
msgid ""
|
||||
"If you want a photo to be deleted, please let us know: <a href=\"mailto:"
|
||||
"photos@crans.org?subject=[ABUS] Nouvelle requête\" class=\"btn btn-dark btn-"
|
||||
"sm\">Abuse request</a>"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:33
|
||||
msgid ""
|
||||
"If you want to obtain the right to upload pictures, please let us know: <a "
|
||||
"href=\"mailto:photos@crans.org?subject=[Photographe] Demande de droits "
|
||||
"photographe\" class=\"btn btn-dark btn-sm\">Become a photograph</a>"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:39
|
||||
msgid "Last galleries"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:50
|
||||
msgid "Connected as"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/index.html:53
|
||||
msgid "Select another language:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/socialaccount/connections.html:6
|
||||
msgid "Account Connections"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/socialaccount/connections.html:23
|
||||
msgid ""
|
||||
"You can sign in to your account using any of the following third party "
|
||||
"accounts:"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/socialaccount/connections.html:51
|
||||
msgid ""
|
||||
"You currently have no social network accounts connected to this account."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/socialaccount/connections.html:54
|
||||
msgid "Add a 3rd Party Account"
|
||||
msgstr ""
|
||||
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-10-23 15:29+0000\n"
|
||||
"POT-Creation-Date: 2022-01-30 07:09+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
|
@ -108,7 +108,7 @@ msgstr ""
|
|||
msgid "E-mail Addresses"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/account/email.html:9 photo21/templates/base.html:58
|
||||
#: photo21/templates/account/email.html:9 photo21/templates/base.html:59
|
||||
#: photo21/templates/socialaccount/connections.html:9
|
||||
msgid "Account"
|
||||
msgstr "Compte"
|
||||
|
|
@ -225,40 +225,96 @@ msgstr ""
|
|||
msgid "The ENS Paris-Saclay pictures server."
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:36
|
||||
#: photo21/templates/base.html:37
|
||||
msgid "Galleries"
|
||||
msgstr "Galeries"
|
||||
|
||||
#: photo21/templates/base.html:41 photologue_custom/forms.py:76
|
||||
#: photologue_custom/templates/photologue/upload.html:6
|
||||
#: photologue_custom/templates/photologue/upload.html:54
|
||||
#: photo21/templates/base.html:42
|
||||
msgid "Upload"
|
||||
msgstr "Téléversement"
|
||||
|
||||
#: photo21/templates/base.html:46
|
||||
#: photo21/templates/base.html:47
|
||||
msgid "Manage"
|
||||
msgstr "Gestion"
|
||||
|
||||
#: photo21/templates/base.html:67
|
||||
#: photo21/templates/base.html:68
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:77
|
||||
#: photo21/templates/base.html:78
|
||||
msgid "Log in"
|
||||
msgstr ""
|
||||
|
||||
#: photo21/templates/base.html:86
|
||||
#: photo21/templates/base.html:87
|
||||
msgid "Sign up"
|
||||
msgstr "Inscription"
|
||||
|
||||
#: photo21/templates/base.html:107
|
||||
#: photo21/templates/base.html:109
|
||||
msgid "Source code"
|
||||
msgstr "Code source"
|
||||
|
||||
#: photo21/templates/index.html:49
|
||||
#: photo21/templates/index.html:6
|
||||
msgid "Home"
|
||||
msgstr "Accueil"
|
||||
|
||||
#: photo21/templates/index.html:9
|
||||
msgid "Welcome to the pictures server!"
|
||||
msgstr "Bienvenue sur le serveur photos !"
|
||||
|
||||
#: photo21/templates/index.html:11
|
||||
msgid ""
|
||||
"This website aims to collect the pictures and movies taken in the student "
|
||||
"life of ENS Paris-Saclay-Saclay or involving its students."
|
||||
msgstr ""
|
||||
"Ce site à pour objectif de recenser les photos et films pris dans la vie "
|
||||
"associative de l'ENS Paris-Saclay ou impliquant des <b>K</b>chanais."
|
||||
|
||||
#: photo21/templates/index.html:18
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The pictures are visible in <a href=\"%(gallery_archive_url)s\">the "
|
||||
"galleries</a> and are downloadable. <b>However, the agreement of the "
|
||||
"photographer and the persons present on the photo is necessary before any "
|
||||
"republication on another platform. </b>"
|
||||
msgstr ""
|
||||
"Les photos sont visibles dans <a href=\"%(gallery_archive_url)s\">les "
|
||||
"galeries</a> et sont téléchargeables. <b>Toutefois, l'accord de la ou du "
|
||||
"photographe et des personnes présentes sur la photo est nécessaire avant "
|
||||
"toute republication sur un autre site.</b>"
|
||||
|
||||
#: photo21/templates/index.html:27
|
||||
msgid ""
|
||||
"If you want a photo to be deleted, please let us know: <a href=\"mailto:"
|
||||
"photos@crans.org?subject=[ABUS] Nouvelle requête\" class=\"btn btn-dark btn-"
|
||||
"sm\">Abuse request</a>"
|
||||
msgstr ""
|
||||
"Si vous souhaitez qu'une photo soit supprimée, signalez le nous : <a href="
|
||||
"\"mailto:photos@crans.org?subject=[ABUS] Nouvelle requête\" class=\"btn btn-"
|
||||
"dark btn-sm\">Signaler un abus</a>"
|
||||
|
||||
#: photo21/templates/index.html:33
|
||||
msgid ""
|
||||
"If you want to obtain the right to upload pictures, please let us know: <a "
|
||||
"href=\"mailto:photos@crans.org?subject=[Photographe] Demande de droits "
|
||||
"photographe\" class=\"btn btn-dark btn-sm\">Become a photograph</a>"
|
||||
msgstr ""
|
||||
"Si vous souhaitez obtenir les droits photographes pour téléverser vos "
|
||||
"photos, signalez le nous : <a href=\"mailto:photos@crans.org?"
|
||||
"subject=[Photographe] Demande de droits photographe\" class=\"btn btn-dark "
|
||||
"btn-sm\">Devenir photographe</a>"
|
||||
|
||||
#: photo21/templates/index.html:39
|
||||
msgid "Last galleries"
|
||||
msgstr "Galeries récentes"
|
||||
|
||||
#: photo21/templates/index.html:50
|
||||
msgid "Connected as"
|
||||
msgstr "Connecté en tant que"
|
||||
|
||||
#: photo21/templates/index.html:53
|
||||
msgid "Select another language:"
|
||||
msgstr "Changer de langue :"
|
||||
|
||||
#: photo21/templates/socialaccount/connections.html:6
|
||||
msgid "Account Connections"
|
||||
msgstr ""
|
||||
|
|
@ -278,116 +334,47 @@ msgstr ""
|
|||
msgid "Add a 3rd Party Account"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/admin.py:45 photologue_custom/models.py:51
|
||||
msgid "owner"
|
||||
msgstr "propriétaire"
|
||||
#~ msgid "owner"
|
||||
#~ msgstr "propriétaire"
|
||||
|
||||
#: photologue_custom/forms.py:34
|
||||
msgid "Gallery"
|
||||
msgstr "Galerie"
|
||||
#~ msgid "Gallery"
|
||||
#~ msgstr "Galerie"
|
||||
|
||||
#: photologue_custom/forms.py:36
|
||||
msgid "-- Create a new gallery --"
|
||||
msgstr "-- Créer une nouvelle galerie --"
|
||||
#~ msgid "-- Create a new gallery --"
|
||||
#~ msgstr "-- Créer une nouvelle galerie --"
|
||||
|
||||
#: photologue_custom/forms.py:37
|
||||
msgid ""
|
||||
"Select a gallery to add these images to. Leave this empty to create a new "
|
||||
"gallery from the supplied title."
|
||||
msgstr ""
|
||||
#~ msgid "New gallery title"
|
||||
#~ msgstr "Titre de la nouvelle galerie"
|
||||
|
||||
#: photologue_custom/forms.py:41
|
||||
msgid "New gallery title"
|
||||
msgstr "Titre de la nouvelle galerie"
|
||||
#~ msgid "New gallery event start date"
|
||||
#~ msgstr "Date de début de l'évènement de la nouvelle galerie"
|
||||
|
||||
#: photologue_custom/forms.py:46
|
||||
msgid "New gallery event start date"
|
||||
msgstr "Date de début de l'évènement de la nouvelle galerie"
|
||||
#~ msgid "New gallery event end date"
|
||||
#~ msgstr "Date de fin de l'évènement de la nouvelle galerie"
|
||||
|
||||
#: photologue_custom/forms.py:51
|
||||
msgid "New gallery event end date"
|
||||
msgstr "Date de fin de l'évènement de la nouvelle galerie"
|
||||
#~ msgid "New gallery tags"
|
||||
#~ msgstr "Tags de la nouvelle galerie"
|
||||
|
||||
#: photologue_custom/forms.py:57
|
||||
msgid "New gallery tags"
|
||||
msgstr "Tags de la nouvelle galerie"
|
||||
#~ msgid "start date"
|
||||
#~ msgstr "date de début"
|
||||
|
||||
#: photologue_custom/forms.py:59
|
||||
msgid ""
|
||||
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
||||
msgstr ""
|
||||
#~ msgid "end date"
|
||||
#~ msgstr "date de fin"
|
||||
|
||||
#: photologue_custom/forms.py:82
|
||||
msgid "A gallery with that title already exists."
|
||||
msgstr ""
|
||||
#~ msgid "license"
|
||||
#~ msgstr "licence"
|
||||
|
||||
#: photologue_custom/forms.py:91
|
||||
msgid "Select an existing gallery, or enter a title for a new gallery."
|
||||
msgstr ""
|
||||
#~ msgid "to"
|
||||
#~ msgstr "au"
|
||||
|
||||
#: photologue_custom/models.py:23
|
||||
msgid "start date"
|
||||
msgstr "date de début"
|
||||
#~ msgid "All pictures"
|
||||
#~ msgstr "Toutes les photos"
|
||||
|
||||
#: photologue_custom/models.py:28
|
||||
msgid "end date"
|
||||
msgstr "date de fin"
|
||||
#~ msgid "Download all gallery"
|
||||
#~ msgstr "Télécharger toute la galerie"
|
||||
|
||||
#: photologue_custom/models.py:56
|
||||
msgid "license"
|
||||
msgstr "licence"
|
||||
#~ msgid "Drag and drop photos here"
|
||||
#~ msgstr "Glissez et déposez les photos ici"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:7
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:12
|
||||
msgid "Latest photo galleries"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:18
|
||||
msgid "Filter by year"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:35
|
||||
msgid "No galleries were found"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:7
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:12
|
||||
#, python-format
|
||||
msgid "Galleries for %(show_year)s"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:17
|
||||
msgid "View all galleries"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:29
|
||||
msgid "No galleries were found."
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:38
|
||||
msgid "to"
|
||||
msgstr "au"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:54
|
||||
msgid "All pictures"
|
||||
msgstr "Toutes les photos"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:75
|
||||
msgid "Download all gallery"
|
||||
msgstr "Télécharger toute la galerie"
|
||||
|
||||
#: photologue_custom/templates/photologue/photo_detail.html:13
|
||||
msgid "Published"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/photo_detail.html:25
|
||||
msgid "This photo is found in the following galleries"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/upload.html:59
|
||||
msgid "Drag and drop photos here"
|
||||
msgstr "Glissez et déposez les photos ici"
|
||||
|
||||
#: photologue_custom/templates/photologue/upload.html:63
|
||||
msgid "Owner will be"
|
||||
msgstr "Le propriétaire sera"
|
||||
#~ msgid "Owner will be"
|
||||
#~ msgstr "Le propriétaire sera"
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ INSTALLED_APPS = [
|
|||
'crispy_forms',
|
||||
'photologue_custom',
|
||||
'photologue',
|
||||
'sortedm2m',
|
||||
'taggit',
|
||||
]
|
||||
|
||||
|
|
@ -235,7 +234,3 @@ SOCIALACCOUNT_PROVIDERS = {
|
|||
|
||||
# Use Bootstrap forms
|
||||
CRISPY_TEMPLATE_PACK = 'bootstrap4'
|
||||
|
||||
# Photologue
|
||||
PHOTOLOGUE_GALLERY_SAMPLE_SIZE = 1
|
||||
PHOTOLOGUE_DIR = '.'
|
||||
|
|
|
|||
12
photo21/static/bootstrap5/css/bootstrap-dark-plugin.min.css
vendored
Normal file
12
photo21/static/bootstrap5/css/bootstrap-dark-plugin.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
{% block head_title %}{% trans "Sign In" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card bg-light mx-auto" style="max-width: 35rem;">
|
||||
<div class="card mx-auto" style="max-width: 35rem;">
|
||||
<h3 class="card-header text-center">
|
||||
{% trans "Sign In" %}
|
||||
</h3>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
{% block head_title %}{% trans "Signup" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card bg-light">
|
||||
<div class="card">
|
||||
<h3 class="card-header text-center">
|
||||
{% trans "Sign Up" %}
|
||||
</h3>
|
||||
|
|
|
|||
|
|
@ -11,12 +11,13 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||
<title>{% block title %}{{ title }}{% endblock title %} - {{ request.site.name }}</title>
|
||||
<meta name="description" content="{% trans "The ENS Paris-Saclay pictures server." %}">
|
||||
<link rel="stylesheet" href="{% static "bootstrap5/css/bootstrap.min.css" %}">
|
||||
<link rel="stylesheet" href="{% static "bootstrap5/css/bootstrap-dark-plugin.min.css" %}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{% static "favicon-16x16.png" %}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{% static "favicon-32x32.png" %}">
|
||||
<meta name="theme-color" content="#212529">
|
||||
{% block extracss %}{% endblock %}
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark py-0">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{% url 'index' %}">
|
||||
|
|
|
|||
|
|
@ -3,31 +3,40 @@
|
|||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% endcomment %}
|
||||
{% load i18n %}
|
||||
{% block title %}Accueil{% endblock %}
|
||||
{% block title %}{% trans "Home" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Bienvenue sur le serveur photos !</h2>
|
||||
<h2>{% trans "Welcome to the pictures server!" %}</h2>
|
||||
<p>
|
||||
Ce site à pour objectif de recenser les photos et films pris dans la vie
|
||||
associative de l'ENS Paris-Saclay ou impliquant des
|
||||
<b>K</b>chanais.
|
||||
{% blocktranslate trimmed %}
|
||||
This website aims to collect the pictures and movies taken in the student
|
||||
life of ENS Paris-Saclay-Saclay or involving its students.
|
||||
{% endblocktranslate %}
|
||||
</p>
|
||||
<p>
|
||||
Les photos sont visibles dans <a href="{% url 'photologue:pl-gallery-archive' %}">les galeries</a> et téléchargeables, toutefois,
|
||||
<b>l'accord de la ou du photographe et des personnes présentes sur la
|
||||
photo est nécessaire avant toute republication sur un autre site.</b>
|
||||
{% url 'photologue:pl-gallery-archive' as gallery_archive_url %}
|
||||
{% blocktranslate trimmed %}
|
||||
The pictures are visible in <a href="{{ gallery_archive_url }}">the galleries</a>
|
||||
and are downloadable.
|
||||
<b>However, the agreement of the photographer and the persons present
|
||||
on the photo is necessary before any republication on another platform. </b>
|
||||
{% endblocktranslate %}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Si vous souhaitez qu'une photo soit supprimée, signalez le nous :
|
||||
<a href="mailto:photos@crans.org?subject=[ABUS] Nouvelle requête" class="btn btn-dark btn-sm">Signaler un abus</a>
|
||||
{% blocktranslate trimmed %}
|
||||
If you want a photo to be deleted, please let us know:
|
||||
<a href="mailto:photos@crans.org?subject=[ABUS] Nouvelle requête" class="btn btn-dark btn-sm">Abuse request</a>
|
||||
{% endblocktranslate %}
|
||||
</p>
|
||||
<p>
|
||||
Si vous souhaitez obtenir les droits photographes pour téléverser vos photos, signalez le nous :
|
||||
<a href="mailto:photos@crans.org?subject=[Photographe] Demande de droits photographe" class="btn btn-dark btn-sm">Devenir photographe</a>
|
||||
{% blocktranslate trimmed %}
|
||||
If you want to obtain the right to upload pictures, please let us know:
|
||||
<a href="mailto:photos@crans.org?subject=[Photographe] Demande de droits photographe" class="btn btn-dark btn-sm">Become a photograph</a>
|
||||
{% endblocktranslate %}
|
||||
</p>
|
||||
|
||||
<h3>Dernières galeries</h3>
|
||||
<h3>{% trans "Last galleries" %}</h3>
|
||||
<div class="row mb-2">
|
||||
{% for gallery in object_list %}
|
||||
<div class="col-md-3">
|
||||
|
|
@ -36,20 +45,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<h3>Participez et faites vivre le serveur photos :</h3>
|
||||
<ul>
|
||||
<li>Devenez photographe et téléversez vos photos</li>
|
||||
<li>Reportez-nous toute anomalie dans la nouvelle interface ou toute difficulté rencontrée : fautes d'orthographes, bugs, mauvaise ergonomie…</li>
|
||||
<li>Envoyez-nous vos suggestions à <a href="mailto:photos@crans.org">photos@crans.org</a>.</li>
|
||||
<li>Si l'amélioration ou la gestion du serveur vous intéresse et pour en savoir plus, <a href="mailto:photos@crans.org">contactez-nous</a>.</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
{% trans "Connected as" %} <code>{{ request.user.username }}</code>.
|
||||
<form action="{% url 'set_language' %}" method="post" style="max-width: 10em;">
|
||||
<form action="{% url 'set_language' %}" method="post" style="max-width: 15em;">
|
||||
{% csrf_token %}
|
||||
Changer la langue :
|
||||
{% trans "Select another language:" %}
|
||||
<select title="language" name="language" class="form-control form-control-sm" onchange="this.form.submit()">
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
{% get_available_languages as LANGUAGES %}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,6 @@ class MediaAccess(LoginRequiredMixin, View):
|
|||
|
||||
|
||||
class IndexView(LoginRequiredMixin, ListView):
|
||||
queryset = Gallery.objects.on_site().is_public()
|
||||
queryset = Gallery.objects.filter(is_public=True)
|
||||
paginate_by = 4
|
||||
template_name = "index.html"
|
||||
|
|
|
|||
0
photologue/__init__.py
Normal file
0
photologue/__init__.py
Normal file
24
photologue/admin.py
Normal file
24
photologue/admin.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Gallery, Photo
|
||||
|
||||
|
||||
class GalleryAdmin(admin.ModelAdmin):
|
||||
list_display = ('title', 'date_added', 'photo_count', 'is_public')
|
||||
list_filter = ['date_added', 'is_public']
|
||||
date_hierarchy = 'date_added'
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
model = Gallery
|
||||
autocomplete_fields = ['photos', ]
|
||||
search_fields = ['title', ]
|
||||
|
||||
|
||||
class PhotoAdmin(admin.ModelAdmin):
|
||||
list_display = ('title', 'date_taken', 'date_added',
|
||||
'is_public', 'view_count', 'admin_thumbnail')
|
||||
list_filter = ['date_added', 'is_public']
|
||||
search_fields = ['title', 'slug', 'caption']
|
||||
list_per_page = 10
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
readonly_fields = ('date_taken',)
|
||||
model = Photo
|
||||
6
photologue/apps.py
Normal file
6
photologue/apps.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PhotologueConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.AutoField'
|
||||
name = 'photologue'
|
||||
431
photologue/locale/de/LC_MESSAGES/django.po
Normal file
431
photologue/locale/de/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
#
|
||||
# Translators:
|
||||
# Translators:
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2009
|
||||
# Jannis Vajen, 2012-2016
|
||||
# Martin Darmüntzel <martin@trivialanalog.de>, 2014
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Photologue\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-01-30 07:09+0000\n"
|
||||
"PO-Revision-Date: 2017-12-03 14:47+0000\n"
|
||||
"Last-Translator: Richard Barran <richard@arbee-design.co.uk>\n"
|
||||
"Language-Team: German (http://www.transifex.com/richardbarran/django-"
|
||||
"photologue/language/de/)\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"
|
||||
|
||||
#: photologue/models.py:86
|
||||
msgid "Very Low"
|
||||
msgstr "Sehr niedrig"
|
||||
|
||||
#: photologue/models.py:87
|
||||
msgid "Low"
|
||||
msgstr "Niedrig"
|
||||
|
||||
#: photologue/models.py:88
|
||||
msgid "Medium-Low"
|
||||
msgstr "Mittel-niedrig"
|
||||
|
||||
#: photologue/models.py:89
|
||||
msgid "Medium"
|
||||
msgstr "Mittel"
|
||||
|
||||
#: photologue/models.py:90
|
||||
msgid "Medium-High"
|
||||
msgstr "Mittel-hoch"
|
||||
|
||||
#: photologue/models.py:91
|
||||
msgid "High"
|
||||
msgstr "Hoch"
|
||||
|
||||
#: photologue/models.py:92
|
||||
msgid "Very High"
|
||||
msgstr "Sehr hoch"
|
||||
|
||||
#: photologue/models.py:97
|
||||
msgid "Top"
|
||||
msgstr "Oben"
|
||||
|
||||
#: photologue/models.py:98
|
||||
msgid "Right"
|
||||
msgstr "Rechts"
|
||||
|
||||
#: photologue/models.py:99
|
||||
msgid "Bottom"
|
||||
msgstr "Unten"
|
||||
|
||||
#: photologue/models.py:100
|
||||
msgid "Left"
|
||||
msgstr "Links"
|
||||
|
||||
#: photologue/models.py:101
|
||||
msgid "Center (Default)"
|
||||
msgstr "Mitte (Standard)"
|
||||
|
||||
#: photologue/models.py:105
|
||||
msgid "Flip left to right"
|
||||
msgstr "Horizontal spiegeln"
|
||||
|
||||
#: photologue/models.py:106
|
||||
msgid "Flip top to bottom"
|
||||
msgstr "Vertikal spiegeln"
|
||||
|
||||
#: photologue/models.py:107
|
||||
msgid "Rotate 90 degrees counter-clockwise"
|
||||
msgstr "Um 90° nach links drehen"
|
||||
|
||||
#: photologue/models.py:108
|
||||
msgid "Rotate 90 degrees clockwise"
|
||||
msgstr "Um 90° nach rechts drehen"
|
||||
|
||||
#: photologue/models.py:109
|
||||
msgid "Rotate 180 degrees"
|
||||
msgstr "Um 180° drehen"
|
||||
|
||||
#: photologue/models.py:119
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Chain multiple filters using the following pattern \"FILTER_ONE->FILTER_TWO-"
|
||||
">FILTER_THREE\". Image filters will be applied in order. The following "
|
||||
"filters are available: %s."
|
||||
msgstr ""
|
||||
"Verkette mehrere Filter in der Art \"FILTER_EINS->FILTER_ZWEI->FILTER_DREI"
|
||||
"\". Bildfilter werden nach der Reihe angewendet. Folgende Filter sind "
|
||||
"verfügbar: %s."
|
||||
|
||||
#: photologue/models.py:141
|
||||
msgid "date published"
|
||||
msgstr "Veröffentlichungsdatum"
|
||||
|
||||
#: photologue/models.py:143 photologue/models.py:474
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: photologue/models.py:146
|
||||
msgid "title slug"
|
||||
msgstr "Kurztitel"
|
||||
|
||||
#: photologue/models.py:149 photologue/models.py:480
|
||||
msgid "A \"slug\" is a unique URL-friendly title for an object."
|
||||
msgstr ""
|
||||
"Ein Kurztitel (\"slug\") ist ein eindeutiger, URL-geeigneter Titel für ein "
|
||||
"Objekt."
|
||||
|
||||
#: photologue/models.py:150
|
||||
msgid "description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
#: photologue/models.py:152 photologue/models.py:485
|
||||
msgid "is public"
|
||||
msgstr "ist öffentlich"
|
||||
|
||||
#: photologue/models.py:154
|
||||
msgid "Public galleries will be displayed in the default views."
|
||||
msgstr "Öffentliche Galerien werden in den Standard-Views angezeigt."
|
||||
|
||||
#: photologue/models.py:158 photologue/models.py:495
|
||||
msgid "photos"
|
||||
msgstr "Fotos"
|
||||
|
||||
#: photologue/models.py:166
|
||||
msgid "gallery"
|
||||
msgstr "Galerie"
|
||||
|
||||
#: photologue/models.py:167
|
||||
msgid "galleries"
|
||||
msgstr "Galerien"
|
||||
|
||||
#: photologue/models.py:202
|
||||
msgid "count"
|
||||
msgstr "Anzahl"
|
||||
|
||||
#: photologue/models.py:210
|
||||
msgid "image"
|
||||
msgstr "Bild"
|
||||
|
||||
#: photologue/models.py:213
|
||||
msgid "date taken"
|
||||
msgstr "Aufnahmedatum"
|
||||
|
||||
#: photologue/models.py:216
|
||||
msgid "Date image was taken; is obtained from the image EXIF data."
|
||||
msgstr ""
|
||||
"Datum, an dem das Foto geschossen wurde; ausgelesen aus den EXIF-Daten."
|
||||
|
||||
#: photologue/models.py:217
|
||||
msgid "view count"
|
||||
msgstr "Anzahl an Aufrufen"
|
||||
|
||||
#: photologue/models.py:220
|
||||
msgid "crop from"
|
||||
msgstr "Beschneiden von"
|
||||
|
||||
#: photologue/models.py:243
|
||||
msgid "An \"admin_thumbnail\" photo size has not been defined."
|
||||
msgstr "Es ist keine Fotogröße \"admin_thumbnail\" definiert."
|
||||
|
||||
#: photologue/models.py:250
|
||||
msgid "Thumbnail"
|
||||
msgstr "Vorschaubild"
|
||||
|
||||
#: photologue/models.py:477
|
||||
msgid "slug"
|
||||
msgstr "Kurztitel"
|
||||
|
||||
#: photologue/models.py:481
|
||||
msgid "caption"
|
||||
msgstr "Bildunterschrift"
|
||||
|
||||
#: photologue/models.py:483
|
||||
msgid "date added"
|
||||
msgstr "Datum des Eintrags"
|
||||
|
||||
#: photologue/models.py:487
|
||||
msgid "Public photographs will be displayed in the default views."
|
||||
msgstr "Öffentliche Fotos werden in den Standard-Views angezeigt."
|
||||
|
||||
#: photologue/models.py:494
|
||||
msgid "photo"
|
||||
msgstr "Foto"
|
||||
|
||||
#: photologue/models.py:556
|
||||
msgid "name"
|
||||
msgstr "Name"
|
||||
|
||||
#: photologue/models.py:560
|
||||
msgid ""
|
||||
"Photo size name should contain only letters, numbers and underscores. "
|
||||
"Examples: \"thumbnail\", \"display\", \"small\", \"main_page_widget\"."
|
||||
msgstr ""
|
||||
"Der Name der Fotogröße darf nur Buchstaben, Zahlen und Unterstriche "
|
||||
"enthalten. Beispiele: \"thumbnail\", \"display\", \"small\", "
|
||||
"\"main_page_widget\"."
|
||||
|
||||
#: photologue/models.py:567
|
||||
msgid "width"
|
||||
msgstr "Breite"
|
||||
|
||||
#: photologue/models.py:570
|
||||
msgid ""
|
||||
"If width is set to \"0\" the image will be scaled to the supplied height."
|
||||
msgstr ""
|
||||
"Wenn die Breite auf \"0\" gesetzt ist, wird das Bild proportional auf die "
|
||||
"angebene Höhe skaliert."
|
||||
|
||||
#: photologue/models.py:571
|
||||
msgid "height"
|
||||
msgstr "Höhe"
|
||||
|
||||
#: photologue/models.py:574
|
||||
msgid ""
|
||||
"If height is set to \"0\" the image will be scaled to the supplied width"
|
||||
msgstr ""
|
||||
"Wenn die Höhe auf \"0\" gesetzt ist, wird das Bild proportional auf die "
|
||||
"angebene Breite skaliert."
|
||||
|
||||
#: photologue/models.py:575
|
||||
msgid "quality"
|
||||
msgstr "Qualität"
|
||||
|
||||
#: photologue/models.py:578
|
||||
msgid "JPEG image quality."
|
||||
msgstr "JPEG-Bildqualität"
|
||||
|
||||
#: photologue/models.py:579
|
||||
msgid "upscale images?"
|
||||
msgstr "Bilder hochskalieren?"
|
||||
|
||||
#: photologue/models.py:581
|
||||
msgid ""
|
||||
"If selected the image will be scaled up if necessary to fit the supplied "
|
||||
"dimensions. Cropped sizes will be upscaled regardless of this setting."
|
||||
msgstr ""
|
||||
"Soll das Bild hochskaliert werden, um das angegebene Format zu erreichen? "
|
||||
"Beschnittene Größen werden unabhängig von dieser Einstellung bei Bedarf "
|
||||
"hochskaliert."
|
||||
|
||||
#: photologue/models.py:585
|
||||
msgid "crop to fit?"
|
||||
msgstr "Zuschneiden?"
|
||||
|
||||
#: photologue/models.py:587
|
||||
msgid ""
|
||||
"If selected the image will be scaled and cropped to fit the supplied "
|
||||
"dimensions."
|
||||
msgstr ""
|
||||
"Soll das Bild auf das angegebene Format skaliert und beschnitten werden?"
|
||||
|
||||
#: photologue/models.py:589
|
||||
msgid "pre-cache?"
|
||||
msgstr "Vorausspeichern?"
|
||||
|
||||
#: photologue/models.py:591
|
||||
msgid "If selected this photo size will be pre-cached as photos are added."
|
||||
msgstr ""
|
||||
"Soll diese Bildgröße im Voraus gespeichert (pre-cached) werden, wenn Fotos "
|
||||
"hinzugefügt werden?"
|
||||
|
||||
#: photologue/models.py:592
|
||||
msgid "increment view count?"
|
||||
msgstr "Bildzähler?"
|
||||
|
||||
#: photologue/models.py:594
|
||||
msgid ""
|
||||
"If selected the image's \"view_count\" will be incremented when this photo "
|
||||
"size is displayed."
|
||||
msgstr ""
|
||||
"Soll der Ansichts-Zähler (view-count) hochgezählt werden, wenn ein Foto "
|
||||
"dieser Größe angezeigt wird?"
|
||||
|
||||
#: photologue/models.py:599
|
||||
msgid "photo size"
|
||||
msgstr "Foto-Größe"
|
||||
|
||||
#: photologue/models.py:600
|
||||
msgid "photo sizes"
|
||||
msgstr "Foto-Größen"
|
||||
|
||||
#: photologue/models.py:617
|
||||
msgid "Can only crop photos if both width and height dimensions are set."
|
||||
msgstr ""
|
||||
"Fotos können nur zugeschnitten werden, wenn Breite und Höhe angegeben sind."
|
||||
|
||||
#: photologue_custom/admin.py:43 photologue_custom/models.py:51
|
||||
msgid "owner"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:34
|
||||
msgid "Gallery"
|
||||
msgstr "Galerie"
|
||||
|
||||
#: photologue_custom/forms.py:36
|
||||
msgid "-- Create a new gallery --"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:37
|
||||
msgid ""
|
||||
"Select a gallery to add these images to. Leave this empty to create a new "
|
||||
"gallery from the supplied title."
|
||||
msgstr ""
|
||||
"Wähle eine Galerie aus, zu der diese Bilder hinzugefügt werden sollen. Lasse "
|
||||
"dieses Feld leer, um eine neue Galerie mit dem angegeben Titel zu erzeugen."
|
||||
|
||||
#: photologue_custom/forms.py:41
|
||||
#, fuzzy
|
||||
#| msgid "View all galleries"
|
||||
msgid "New gallery title"
|
||||
msgstr "Zeige alle Galerien."
|
||||
|
||||
#: photologue_custom/forms.py:46
|
||||
msgid "New gallery event start date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:51
|
||||
msgid "New gallery event end date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:57
|
||||
#, fuzzy
|
||||
#| msgid "gallery"
|
||||
msgid "New gallery tags"
|
||||
msgstr "Galerie"
|
||||
|
||||
#: photologue_custom/forms.py:59
|
||||
msgid ""
|
||||
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:76
|
||||
#: photologue_custom/templates/photologue/upload.html:6
|
||||
#: photologue_custom/templates/photologue/upload.html:73
|
||||
msgid "Upload"
|
||||
msgstr "Hochladen"
|
||||
|
||||
#: photologue_custom/forms.py:82
|
||||
msgid "A gallery with that title already exists."
|
||||
msgstr "Es existiert bereits eine Gallerie mit diesem Titel."
|
||||
|
||||
#: photologue_custom/forms.py:91
|
||||
msgid "Select an existing gallery, or enter a title for a new gallery."
|
||||
msgstr ""
|
||||
"Wähle eine existierende Galerie aus oder gib einen Titel für eine neue "
|
||||
"Galerie ein."
|
||||
|
||||
#: photologue_custom/models.py:23
|
||||
msgid "start date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/models.py:28
|
||||
msgid "end date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/models.py:56
|
||||
msgid "license"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:7
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:12
|
||||
msgid "Latest photo galleries"
|
||||
msgstr "Aktuelle Fotogalerien"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:18
|
||||
msgid "Filter by year"
|
||||
msgstr "Filtere nach Jahr"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:35
|
||||
msgid "No galleries were found"
|
||||
msgstr "Es wurden keine Galerien gefunden."
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:7
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:12
|
||||
#, python-format
|
||||
msgid "Galleries for %(show_year)s"
|
||||
msgstr "Gallerien von %(show_year)s"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:17
|
||||
msgid "View all galleries"
|
||||
msgstr "Zeige alle Galerien."
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:29
|
||||
msgid "No galleries were found."
|
||||
msgstr "Es wurden keine Galerien gefunden."
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:41
|
||||
msgid "to"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:57
|
||||
#, fuzzy
|
||||
#| msgid "All photos"
|
||||
msgid "All pictures"
|
||||
msgstr "Alle Fotos"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:78
|
||||
#, fuzzy
|
||||
#| msgid "View all galleries"
|
||||
msgid "Download all gallery"
|
||||
msgstr "Zeige alle Galerien."
|
||||
|
||||
#: photologue_custom/templates/photologue/photo_detail.html:13
|
||||
msgid "Published"
|
||||
msgstr "Veröffentlicht"
|
||||
|
||||
#: photologue_custom/templates/photologue/photo_detail.html:25
|
||||
msgid "This photo is found in the following galleries"
|
||||
msgstr "Dieses Foto befindet sich in folgenden Galerien"
|
||||
|
||||
#: photologue_custom/templates/photologue/upload.html:78
|
||||
msgid "Drag and drop photos here"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/upload.html:82
|
||||
msgid "Owner will be"
|
||||
msgstr ""
|
||||
427
photologue/locale/es/LC_MESSAGES/django.po
Normal file
427
photologue/locale/es/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,427 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
#
|
||||
# Translators:
|
||||
# Translators:
|
||||
# dmalisani <dmalisani@gmail.com>, 2014
|
||||
# dmalisani <dmalisani@gmail.com>, 2014
|
||||
# Rafa Muñoz Cárdenas <bymenda@gmail.com>, 2009
|
||||
# salvador ortiz <chava.door@gmail.com>, 2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Photologue\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-01-30 07:09+0000\n"
|
||||
"PO-Revision-Date: 2017-12-03 14:46+0000\n"
|
||||
"Last-Translator: Richard Barran <richard@arbee-design.co.uk>\n"
|
||||
"Language-Team: Spanish (Spain) (http://www.transifex.com/richardbarran/"
|
||||
"django-photologue/language/es_ES/)\n"
|
||||
"Language: es_ES\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"
|
||||
|
||||
#: photologue/models.py:86
|
||||
msgid "Very Low"
|
||||
msgstr "Muy bajo"
|
||||
|
||||
#: photologue/models.py:87
|
||||
msgid "Low"
|
||||
msgstr "Bajo"
|
||||
|
||||
#: photologue/models.py:88
|
||||
msgid "Medium-Low"
|
||||
msgstr "Medio-bajo"
|
||||
|
||||
#: photologue/models.py:89
|
||||
msgid "Medium"
|
||||
msgstr "Medio"
|
||||
|
||||
#: photologue/models.py:90
|
||||
msgid "Medium-High"
|
||||
msgstr "Medio-alto"
|
||||
|
||||
#: photologue/models.py:91
|
||||
msgid "High"
|
||||
msgstr "Alto"
|
||||
|
||||
#: photologue/models.py:92
|
||||
msgid "Very High"
|
||||
msgstr "Muy alto"
|
||||
|
||||
#: photologue/models.py:97
|
||||
msgid "Top"
|
||||
msgstr "Arriba"
|
||||
|
||||
#: photologue/models.py:98
|
||||
msgid "Right"
|
||||
msgstr "Derecha"
|
||||
|
||||
#: photologue/models.py:99
|
||||
msgid "Bottom"
|
||||
msgstr "Abajo"
|
||||
|
||||
#: photologue/models.py:100
|
||||
msgid "Left"
|
||||
msgstr "Izquierda"
|
||||
|
||||
#: photologue/models.py:101
|
||||
msgid "Center (Default)"
|
||||
msgstr "Centro (por defecto)"
|
||||
|
||||
#: photologue/models.py:105
|
||||
msgid "Flip left to right"
|
||||
msgstr "Voltear de izquerda a derecha"
|
||||
|
||||
#: photologue/models.py:106
|
||||
msgid "Flip top to bottom"
|
||||
msgstr "Voltear de arriba a abajo"
|
||||
|
||||
#: photologue/models.py:107
|
||||
msgid "Rotate 90 degrees counter-clockwise"
|
||||
msgstr "Rotar 90 grados en sentido horario"
|
||||
|
||||
#: photologue/models.py:108
|
||||
msgid "Rotate 90 degrees clockwise"
|
||||
msgstr "Rotar 90 grados en sentido antihorario"
|
||||
|
||||
#: photologue/models.py:109
|
||||
msgid "Rotate 180 degrees"
|
||||
msgstr "Rotar 180 grados"
|
||||
|
||||
#: photologue/models.py:119
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Chain multiple filters using the following pattern \"FILTER_ONE->FILTER_TWO-"
|
||||
">FILTER_THREE\". Image filters will be applied in order. The following "
|
||||
"filters are available: %s."
|
||||
msgstr ""
|
||||
"Encadene múltiples filtros usando el siguiente patrón \"FILTRO_UNO-"
|
||||
">FILTRO_DOS->FILTRO_TRES\". Los filtros de imagen se aplicarán en orden. Los "
|
||||
"siguientes filtros están disponibles: %s."
|
||||
|
||||
#: photologue/models.py:141
|
||||
msgid "date published"
|
||||
msgstr "fecha de publicación"
|
||||
|
||||
#: photologue/models.py:143 photologue/models.py:474
|
||||
msgid "title"
|
||||
msgstr "título"
|
||||
|
||||
#: photologue/models.py:146
|
||||
msgid "title slug"
|
||||
msgstr "título slug"
|
||||
|
||||
#: photologue/models.py:149 photologue/models.py:480
|
||||
msgid "A \"slug\" is a unique URL-friendly title for an object."
|
||||
msgstr "Un \"slug\" es un único título URL-amigable para un objeto."
|
||||
|
||||
#: photologue/models.py:150
|
||||
msgid "description"
|
||||
msgstr "descripción"
|
||||
|
||||
#: photologue/models.py:152 photologue/models.py:485
|
||||
msgid "is public"
|
||||
msgstr "es público"
|
||||
|
||||
#: photologue/models.py:154
|
||||
msgid "Public galleries will be displayed in the default views."
|
||||
msgstr "Las galerías públicas serán mostradas en las vistas por defecto."
|
||||
|
||||
#: photologue/models.py:158 photologue/models.py:495
|
||||
msgid "photos"
|
||||
msgstr "fotos"
|
||||
|
||||
#: photologue/models.py:166
|
||||
msgid "gallery"
|
||||
msgstr "galería"
|
||||
|
||||
#: photologue/models.py:167
|
||||
msgid "galleries"
|
||||
msgstr "galerías"
|
||||
|
||||
#: photologue/models.py:202
|
||||
msgid "count"
|
||||
msgstr "contar"
|
||||
|
||||
#: photologue/models.py:210
|
||||
msgid "image"
|
||||
msgstr "imagen"
|
||||
|
||||
#: photologue/models.py:213
|
||||
msgid "date taken"
|
||||
msgstr "fecha en la que se tomó"
|
||||
|
||||
#: photologue/models.py:216
|
||||
msgid "Date image was taken; is obtained from the image EXIF data."
|
||||
msgstr "La fecha de la imagen fue obtenida por información EXIF de la imagen."
|
||||
|
||||
#: photologue/models.py:217
|
||||
msgid "view count"
|
||||
msgstr "Contador de visitas"
|
||||
|
||||
#: photologue/models.py:220
|
||||
msgid "crop from"
|
||||
msgstr "Recortar desde"
|
||||
|
||||
#: photologue/models.py:243
|
||||
msgid "An \"admin_thumbnail\" photo size has not been defined."
|
||||
msgstr "El tamaño de foto de \"miniatura de admin\" no ha sido definido."
|
||||
|
||||
#: photologue/models.py:250
|
||||
msgid "Thumbnail"
|
||||
msgstr "Miniatura"
|
||||
|
||||
#: photologue/models.py:477
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: photologue/models.py:481
|
||||
msgid "caption"
|
||||
msgstr "pie de foto"
|
||||
|
||||
#: photologue/models.py:483
|
||||
msgid "date added"
|
||||
msgstr "fecha añadida"
|
||||
|
||||
#: photologue/models.py:487
|
||||
msgid "Public photographs will be displayed in the default views."
|
||||
msgstr "Las fotos públicas serán mostradas en las vistas por defecto."
|
||||
|
||||
#: photologue/models.py:494
|
||||
msgid "photo"
|
||||
msgstr "foto"
|
||||
|
||||
#: photologue/models.py:556
|
||||
msgid "name"
|
||||
msgstr "nombre"
|
||||
|
||||
#: photologue/models.py:560
|
||||
msgid ""
|
||||
"Photo size name should contain only letters, numbers and underscores. "
|
||||
"Examples: \"thumbnail\", \"display\", \"small\", \"main_page_widget\"."
|
||||
msgstr ""
|
||||
"El nombre del tamaño solo puede contener letras, números y subrayados. Por "
|
||||
"ejemplo:\"miniaturas\", \"muestra\", \"muestra_principal\"."
|
||||
|
||||
#: photologue/models.py:567
|
||||
msgid "width"
|
||||
msgstr "anchura"
|
||||
|
||||
#: photologue/models.py:570
|
||||
msgid ""
|
||||
"If width is set to \"0\" the image will be scaled to the supplied height."
|
||||
msgstr ""
|
||||
"Si la anchura se establece a \"0\" la imagen será escalada hasta la altura "
|
||||
"proporcionada"
|
||||
|
||||
#: photologue/models.py:571
|
||||
msgid "height"
|
||||
msgstr "altura"
|
||||
|
||||
#: photologue/models.py:574
|
||||
msgid ""
|
||||
"If height is set to \"0\" the image will be scaled to the supplied width"
|
||||
msgstr ""
|
||||
"Si la altura se establece a \"0\" la imagen será escalada hasta la anchura "
|
||||
"proporcionada"
|
||||
|
||||
#: photologue/models.py:575
|
||||
msgid "quality"
|
||||
msgstr "calidad"
|
||||
|
||||
#: photologue/models.py:578
|
||||
msgid "JPEG image quality."
|
||||
msgstr "Calidad de imagen JPEG."
|
||||
|
||||
#: photologue/models.py:579
|
||||
msgid "upscale images?"
|
||||
msgstr "¿Aumentar imágenes?"
|
||||
|
||||
#: photologue/models.py:581
|
||||
msgid ""
|
||||
"If selected the image will be scaled up if necessary to fit the supplied "
|
||||
"dimensions. Cropped sizes will be upscaled regardless of this setting."
|
||||
msgstr ""
|
||||
"Si se selecciona la imagen será aumentada si es necesario para ajustarse a "
|
||||
"las dimensiones proporcionadas. Los tamaños recortados serán aumentados de "
|
||||
"acuerdo a esta opción."
|
||||
|
||||
#: photologue/models.py:585
|
||||
msgid "crop to fit?"
|
||||
msgstr "¿Recortar hasta ajustar?"
|
||||
|
||||
#: photologue/models.py:587
|
||||
msgid ""
|
||||
"If selected the image will be scaled and cropped to fit the supplied "
|
||||
"dimensions."
|
||||
msgstr ""
|
||||
"Si se selecciona la imagen será escalada y recortada para ajustarse a las "
|
||||
"dimensiones proporcionadas."
|
||||
|
||||
#: photologue/models.py:589
|
||||
msgid "pre-cache?"
|
||||
msgstr "¿pre-cachear?"
|
||||
|
||||
#: photologue/models.py:591
|
||||
msgid "If selected this photo size will be pre-cached as photos are added."
|
||||
msgstr ""
|
||||
"Si se selecciona, este tamaño de foto será pre-cacheado cuando se añadan "
|
||||
"nuevas fotos."
|
||||
|
||||
#: photologue/models.py:592
|
||||
msgid "increment view count?"
|
||||
msgstr "¿incrementar contador de visualizaciones?"
|
||||
|
||||
#: photologue/models.py:594
|
||||
msgid ""
|
||||
"If selected the image's \"view_count\" will be incremented when this photo "
|
||||
"size is displayed."
|
||||
msgstr ""
|
||||
"Si se selecciona el \"contador de visualizaciones\" se incrementará cuando "
|
||||
"esta foto sea visualizada."
|
||||
|
||||
#: photologue/models.py:599
|
||||
msgid "photo size"
|
||||
msgstr "tamaño de foto"
|
||||
|
||||
#: photologue/models.py:600
|
||||
msgid "photo sizes"
|
||||
msgstr "tamaños de foto"
|
||||
|
||||
#: photologue/models.py:617
|
||||
msgid "Can only crop photos if both width and height dimensions are set."
|
||||
msgstr "Solo puede recortar las fotos si ancho y alto están establecidos."
|
||||
|
||||
#: photologue_custom/admin.py:43 photologue_custom/models.py:51
|
||||
msgid "owner"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:34
|
||||
msgid "Gallery"
|
||||
msgstr "Galería"
|
||||
|
||||
#: photologue_custom/forms.py:36
|
||||
msgid "-- Create a new gallery --"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:37
|
||||
msgid ""
|
||||
"Select a gallery to add these images to. Leave this empty to create a new "
|
||||
"gallery from the supplied title."
|
||||
msgstr ""
|
||||
"Seleccione una galería para agregarle estas imágenes. Déjelo vacío para "
|
||||
"crear una nueva galería a partir de este título."
|
||||
|
||||
#: photologue_custom/forms.py:41
|
||||
#, fuzzy
|
||||
#| msgid "View all galleries"
|
||||
msgid "New gallery title"
|
||||
msgstr "Ver todas las galerías"
|
||||
|
||||
#: photologue_custom/forms.py:46
|
||||
msgid "New gallery event start date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:51
|
||||
msgid "New gallery event end date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:57
|
||||
#, fuzzy
|
||||
#| msgid "gallery"
|
||||
msgid "New gallery tags"
|
||||
msgstr "galería"
|
||||
|
||||
#: photologue_custom/forms.py:59
|
||||
msgid ""
|
||||
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:76
|
||||
#: photologue_custom/templates/photologue/upload.html:6
|
||||
#: photologue_custom/templates/photologue/upload.html:73
|
||||
msgid "Upload"
|
||||
msgstr "Subir"
|
||||
|
||||
#: photologue_custom/forms.py:82
|
||||
msgid "A gallery with that title already exists."
|
||||
msgstr "Ya existe una galería con ese título."
|
||||
|
||||
#: photologue_custom/forms.py:91
|
||||
msgid "Select an existing gallery, or enter a title for a new gallery."
|
||||
msgstr ""
|
||||
"Seleccione una galería existente o ingrese un nuevo nombre para la galería."
|
||||
|
||||
#: photologue_custom/models.py:23
|
||||
msgid "start date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/models.py:28
|
||||
msgid "end date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/models.py:56
|
||||
msgid "license"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:7
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:12
|
||||
msgid "Latest photo galleries"
|
||||
msgstr "Fotos de galerías mas recientes"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:18
|
||||
msgid "Filter by year"
|
||||
msgstr "Filtrar por año"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:35
|
||||
msgid "No galleries were found"
|
||||
msgstr "No se encontraron galerías"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:7
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:12
|
||||
#, python-format
|
||||
msgid "Galleries for %(show_year)s"
|
||||
msgstr "Galerías por %(show_year)s"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:17
|
||||
msgid "View all galleries"
|
||||
msgstr "Ver todas las galerías"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:29
|
||||
msgid "No galleries were found."
|
||||
msgstr "No se encontraron galerías"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:41
|
||||
msgid "to"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:57
|
||||
#, fuzzy
|
||||
#| msgid "All photos"
|
||||
msgid "All pictures"
|
||||
msgstr "Todas las fotos"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:78
|
||||
#, fuzzy
|
||||
#| msgid "View all galleries"
|
||||
msgid "Download all gallery"
|
||||
msgstr "Ver todas las galerías"
|
||||
|
||||
#: photologue_custom/templates/photologue/photo_detail.html:13
|
||||
msgid "Published"
|
||||
msgstr "Publicado"
|
||||
|
||||
#: photologue_custom/templates/photologue/photo_detail.html:25
|
||||
msgid "This photo is found in the following galleries"
|
||||
msgstr "Esta foto se encontró en las siguientes galerías"
|
||||
|
||||
#: photologue_custom/templates/photologue/upload.html:78
|
||||
msgid "Drag and drop photos here"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/upload.html:82
|
||||
msgid "Owner will be"
|
||||
msgstr ""
|
||||
433
photologue/locale/fr/LC_MESSAGES/django.po
Normal file
433
photologue/locale/fr/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
#
|
||||
# Translators:
|
||||
# Translators:
|
||||
# Matthieu Payet <matthieu.payet4@gmail.com>, 2017
|
||||
# Théophane Hufschmitt <huf31@gmx.fr>, 2014
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Photologue\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-01-30 07:09+0000\n"
|
||||
"PO-Revision-Date: 2017-12-03 14:47+0000\n"
|
||||
"Last-Translator: Richard Barran <richard@arbee-design.co.uk>\n"
|
||||
"Language-Team: French (http://www.transifex.com/richardbarran/django-"
|
||||
"photologue/language/fr/)\n"
|
||||
"Language: fr\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"
|
||||
|
||||
#: photologue/models.py:86
|
||||
msgid "Very Low"
|
||||
msgstr "Très Bas"
|
||||
|
||||
#: photologue/models.py:87
|
||||
msgid "Low"
|
||||
msgstr "Bas"
|
||||
|
||||
#: photologue/models.py:88
|
||||
msgid "Medium-Low"
|
||||
msgstr "Moyen-Bas"
|
||||
|
||||
#: photologue/models.py:89
|
||||
msgid "Medium"
|
||||
msgstr "Moyen"
|
||||
|
||||
#: photologue/models.py:90
|
||||
msgid "Medium-High"
|
||||
msgstr "Moyen-Haut"
|
||||
|
||||
#: photologue/models.py:91
|
||||
msgid "High"
|
||||
msgstr "Haut"
|
||||
|
||||
#: photologue/models.py:92
|
||||
msgid "Very High"
|
||||
msgstr "Très Haut"
|
||||
|
||||
#: photologue/models.py:97
|
||||
msgid "Top"
|
||||
msgstr "Sommet"
|
||||
|
||||
#: photologue/models.py:98
|
||||
msgid "Right"
|
||||
msgstr "Droite"
|
||||
|
||||
#: photologue/models.py:99
|
||||
msgid "Bottom"
|
||||
msgstr "Bas"
|
||||
|
||||
#: photologue/models.py:100
|
||||
msgid "Left"
|
||||
msgstr "Gauche"
|
||||
|
||||
#: photologue/models.py:101
|
||||
msgid "Center (Default)"
|
||||
msgstr "Centré (par défaut)"
|
||||
|
||||
#: photologue/models.py:105
|
||||
msgid "Flip left to right"
|
||||
msgstr "Inversion de gauche à droite"
|
||||
|
||||
#: photologue/models.py:106
|
||||
msgid "Flip top to bottom"
|
||||
msgstr "Inversion de haut en bas"
|
||||
|
||||
#: photologue/models.py:107
|
||||
msgid "Rotate 90 degrees counter-clockwise"
|
||||
msgstr "Rotation de 90 degrés dans le sens anti-horloger"
|
||||
|
||||
#: photologue/models.py:108
|
||||
msgid "Rotate 90 degrees clockwise"
|
||||
msgstr "Rotation de 90 degrés dans le sens horloger"
|
||||
|
||||
#: photologue/models.py:109
|
||||
msgid "Rotate 180 degrees"
|
||||
msgstr "Rotation de 180 degrés"
|
||||
|
||||
#: photologue/models.py:119
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Chain multiple filters using the following pattern \"FILTER_ONE->FILTER_TWO-"
|
||||
">FILTER_THREE\". Image filters will be applied in order. The following "
|
||||
"filters are available: %s."
|
||||
msgstr ""
|
||||
"Faite suivre de multiple filtres en utilisant la forme suivante \"FILTRE_UN-"
|
||||
">FILTRE_DEUX->FILTRE_TROIS\". Les filtres d'image seront appliqués dans "
|
||||
"l'ordre. Les filtres suivants sont disponibles: %s."
|
||||
|
||||
#: photologue/models.py:141
|
||||
msgid "date published"
|
||||
msgstr "date de publication"
|
||||
|
||||
#: photologue/models.py:143 photologue/models.py:474
|
||||
msgid "title"
|
||||
msgstr "titre"
|
||||
|
||||
#: photologue/models.py:146
|
||||
msgid "title slug"
|
||||
msgstr "version abrégée du titre"
|
||||
|
||||
#: photologue/models.py:149 photologue/models.py:480
|
||||
msgid "A \"slug\" is a unique URL-friendly title for an object."
|
||||
msgstr ""
|
||||
"Un \"slug\" est un titre abrégé et unique, compatible avec les URL, pour un "
|
||||
"objet."
|
||||
|
||||
#: photologue/models.py:150
|
||||
msgid "description"
|
||||
msgstr "description"
|
||||
|
||||
#: photologue/models.py:152 photologue/models.py:485
|
||||
msgid "is public"
|
||||
msgstr "est public"
|
||||
|
||||
#: photologue/models.py:154
|
||||
msgid "Public galleries will be displayed in the default views."
|
||||
msgstr "Les galeries publiques seront affichée dans les vues par défaut."
|
||||
|
||||
#: photologue/models.py:158 photologue/models.py:495
|
||||
msgid "photos"
|
||||
msgstr "photos"
|
||||
|
||||
#: photologue/models.py:166
|
||||
msgid "gallery"
|
||||
msgstr "galerie"
|
||||
|
||||
#: photologue/models.py:167
|
||||
msgid "galleries"
|
||||
msgstr "galleries"
|
||||
|
||||
#: photologue/models.py:202
|
||||
msgid "count"
|
||||
msgstr "nombre"
|
||||
|
||||
#: photologue/models.py:210
|
||||
msgid "image"
|
||||
msgstr "image"
|
||||
|
||||
#: photologue/models.py:213
|
||||
msgid "date taken"
|
||||
msgstr "date de prise de vue"
|
||||
|
||||
#: photologue/models.py:216
|
||||
msgid "Date image was taken; is obtained from the image EXIF data."
|
||||
msgstr ""
|
||||
"La date à laquelle l'image a été prise ; obtenue à partir des données EXIF "
|
||||
"de l'image."
|
||||
|
||||
#: photologue/models.py:217
|
||||
msgid "view count"
|
||||
msgstr "nombre"
|
||||
|
||||
#: photologue/models.py:220
|
||||
msgid "crop from"
|
||||
msgstr "découper à partir de"
|
||||
|
||||
#: photologue/models.py:243
|
||||
msgid "An \"admin_thumbnail\" photo size has not been defined."
|
||||
msgstr "Une taille de photo \"admin_thumbnail\" n'a pas encore été définie."
|
||||
|
||||
#: photologue/models.py:250
|
||||
msgid "Thumbnail"
|
||||
msgstr "Miniature"
|
||||
|
||||
#: photologue/models.py:477
|
||||
msgid "slug"
|
||||
msgstr "libellé court"
|
||||
|
||||
#: photologue/models.py:481
|
||||
msgid "caption"
|
||||
msgstr "légende"
|
||||
|
||||
#: photologue/models.py:483
|
||||
msgid "date added"
|
||||
msgstr "date d'ajout"
|
||||
|
||||
#: photologue/models.py:487
|
||||
msgid "Public photographs will be displayed in the default views."
|
||||
msgstr "Les photographies publique seront affichées dans les vues par défaut."
|
||||
|
||||
#: photologue/models.py:494
|
||||
msgid "photo"
|
||||
msgstr "photo"
|
||||
|
||||
#: photologue/models.py:556
|
||||
msgid "name"
|
||||
msgstr "nom"
|
||||
|
||||
#: photologue/models.py:560
|
||||
msgid ""
|
||||
"Photo size name should contain only letters, numbers and underscores. "
|
||||
"Examples: \"thumbnail\", \"display\", \"small\", \"main_page_widget\"."
|
||||
msgstr ""
|
||||
"Le nom de la taille de la photo ne doit contenir que des lettres, des "
|
||||
"chiffres et des caractères de soulignement. Exemples: \"miniature\", "
|
||||
"\"affichage\", \"petit\", \"widget_page_principale\"."
|
||||
|
||||
#: photologue/models.py:567
|
||||
msgid "width"
|
||||
msgstr "largeur"
|
||||
|
||||
#: photologue/models.py:570
|
||||
msgid ""
|
||||
"If width is set to \"0\" the image will be scaled to the supplied height."
|
||||
msgstr ""
|
||||
"Si la largeur est réglée à \"0\" l l'image sera redimensionnée par rapport à "
|
||||
"la hauteur fournie."
|
||||
|
||||
#: photologue/models.py:571
|
||||
msgid "height"
|
||||
msgstr "hauteur"
|
||||
|
||||
#: photologue/models.py:574
|
||||
msgid ""
|
||||
"If height is set to \"0\" the image will be scaled to the supplied width"
|
||||
msgstr ""
|
||||
"Si la hauteur est réglée à \"0\" l l'image sera redimensionnée par rapport à "
|
||||
"la largeur fournie."
|
||||
|
||||
#: photologue/models.py:575
|
||||
msgid "quality"
|
||||
msgstr "qualité"
|
||||
|
||||
#: photologue/models.py:578
|
||||
msgid "JPEG image quality."
|
||||
msgstr "Qualité JPEG de l'image."
|
||||
|
||||
#: photologue/models.py:579
|
||||
msgid "upscale images?"
|
||||
msgstr "agrandir les images ?"
|
||||
|
||||
#: photologue/models.py:581
|
||||
msgid ""
|
||||
"If selected the image will be scaled up if necessary to fit the supplied "
|
||||
"dimensions. Cropped sizes will be upscaled regardless of this setting."
|
||||
msgstr ""
|
||||
"Si sélectionné l'image sera agrandie si nécessaire pour coïncider avec les "
|
||||
"dimensions fournies. Les dimensions ajustées seront agrandies sans prendre "
|
||||
"en compte ce paramètre."
|
||||
|
||||
#: photologue/models.py:585
|
||||
msgid "crop to fit?"
|
||||
msgstr "découper pour adapter à la taille ?"
|
||||
|
||||
#: photologue/models.py:587
|
||||
msgid ""
|
||||
"If selected the image will be scaled and cropped to fit the supplied "
|
||||
"dimensions."
|
||||
msgstr ""
|
||||
"Si sélectionné l'image sera redimensionnée et recadrée pour coïncider avec "
|
||||
"les dimensions fournies."
|
||||
|
||||
#: photologue/models.py:589
|
||||
msgid "pre-cache?"
|
||||
msgstr "mise en cache ?"
|
||||
|
||||
#: photologue/models.py:591
|
||||
msgid "If selected this photo size will be pre-cached as photos are added."
|
||||
msgstr ""
|
||||
"Si sélectionné cette taille de photo sera mise en cache au moment au les "
|
||||
"photos sont ajoutées."
|
||||
|
||||
#: photologue/models.py:592
|
||||
msgid "increment view count?"
|
||||
msgstr "incrémenter le nombre d'affichages ?"
|
||||
|
||||
#: photologue/models.py:594
|
||||
msgid ""
|
||||
"If selected the image's \"view_count\" will be incremented when this photo "
|
||||
"size is displayed."
|
||||
msgstr ""
|
||||
"Si sélectionné le \"view_count\" (nombre d'affichage) de l'image sera "
|
||||
"incrémenté quand cette taille de photo sera affichée."
|
||||
|
||||
#: photologue/models.py:599
|
||||
msgid "photo size"
|
||||
msgstr "taille de la photo"
|
||||
|
||||
#: photologue/models.py:600
|
||||
msgid "photo sizes"
|
||||
msgstr "tailles des photos"
|
||||
|
||||
#: photologue/models.py:617
|
||||
msgid "Can only crop photos if both width and height dimensions are set."
|
||||
msgstr ""
|
||||
"La hauteur et la largeur doivent être toutes les deux définies pour "
|
||||
"retailler des photos."
|
||||
|
||||
#: photologue_custom/admin.py:43 photologue_custom/models.py:51
|
||||
msgid "owner"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:34
|
||||
msgid "Gallery"
|
||||
msgstr "Galerie"
|
||||
|
||||
#: photologue_custom/forms.py:36
|
||||
msgid "-- Create a new gallery --"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:37
|
||||
msgid ""
|
||||
"Select a gallery to add these images to. Leave this empty to create a new "
|
||||
"gallery from the supplied title."
|
||||
msgstr ""
|
||||
"Sélectionner une galerie à laquelle ajouter ces images. Laisser ce champ "
|
||||
"vide pour créer une nouvelle galerie à partir du titre indiqué."
|
||||
|
||||
#: photologue_custom/forms.py:41
|
||||
#, fuzzy
|
||||
#| msgid "View all galleries"
|
||||
msgid "New gallery title"
|
||||
msgstr "Afficher toutes les galeries"
|
||||
|
||||
#: photologue_custom/forms.py:46
|
||||
msgid "New gallery event start date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:51
|
||||
msgid "New gallery event end date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:57
|
||||
#, fuzzy
|
||||
#| msgid "gallery uploads"
|
||||
msgid "New gallery tags"
|
||||
msgstr "gallery uploads"
|
||||
|
||||
#: photologue_custom/forms.py:59
|
||||
msgid ""
|
||||
"Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/forms.py:76
|
||||
#: photologue_custom/templates/photologue/upload.html:6
|
||||
#: photologue_custom/templates/photologue/upload.html:73
|
||||
msgid "Upload"
|
||||
msgstr "Télécharger"
|
||||
|
||||
#: photologue_custom/forms.py:82
|
||||
msgid "A gallery with that title already exists."
|
||||
msgstr "Une galerie portant ce nom existe déjà."
|
||||
|
||||
#: photologue_custom/forms.py:91
|
||||
msgid "Select an existing gallery, or enter a title for a new gallery."
|
||||
msgstr ""
|
||||
"Sélectionner une galerie existante ou entrer un titre pour une nouvelle "
|
||||
"galerie."
|
||||
|
||||
#: photologue_custom/models.py:23
|
||||
msgid "start date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/models.py:28
|
||||
msgid "end date"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/models.py:56
|
||||
msgid "license"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:7
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:12
|
||||
msgid "Latest photo galleries"
|
||||
msgstr "Dernières galeries de photos"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:18
|
||||
msgid "Filter by year"
|
||||
msgstr "Filtrer par année"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive.html:35
|
||||
msgid "No galleries were found"
|
||||
msgstr "Aucune galerie trouvée"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:7
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:12
|
||||
#, python-format
|
||||
msgid "Galleries for %(show_year)s"
|
||||
msgstr "Galeries de %(show_year)s"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:17
|
||||
msgid "View all galleries"
|
||||
msgstr "Afficher toutes les galeries"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_archive_year.html:29
|
||||
msgid "No galleries were found."
|
||||
msgstr "Aucune galerie trouvée."
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:41
|
||||
msgid "to"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:57
|
||||
#, fuzzy
|
||||
#| msgid "All photos"
|
||||
msgid "All pictures"
|
||||
msgstr "Toutes les photos"
|
||||
|
||||
#: photologue_custom/templates/photologue/gallery_detail.html:78
|
||||
#, fuzzy
|
||||
#| msgid "View all galleries"
|
||||
msgid "Download all gallery"
|
||||
msgstr "Afficher toutes les galeries"
|
||||
|
||||
#: photologue_custom/templates/photologue/photo_detail.html:13
|
||||
msgid "Published"
|
||||
msgstr "Publiée le"
|
||||
|
||||
#: photologue_custom/templates/photologue/photo_detail.html:25
|
||||
msgid "This photo is found in the following galleries"
|
||||
msgstr "Cette photo se trouve dans les galeries suivantes"
|
||||
|
||||
#: photologue_custom/templates/photologue/upload.html:78
|
||||
msgid "Drag and drop photos here"
|
||||
msgstr ""
|
||||
|
||||
#: photologue_custom/templates/photologue/upload.html:82
|
||||
msgid "Owner will be"
|
||||
msgstr ""
|
||||
43
photologue/management/commands/plcache.py
Normal file
43
photologue/management/commands/plcache.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Based on https://github.com/richardbarran/django-photologue/
|
||||
# by Richard Barran, BSD-3 licensed
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from photologue.models import ImageModel, PhotoSize
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
help = 'Manages Photologue cache file for the given sizes.'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('sizes',
|
||||
nargs='*',
|
||||
type=str,
|
||||
help='Name of the photosize.')
|
||||
parser.add_argument('--reset',
|
||||
action='store_true',
|
||||
default=False,
|
||||
dest='reset',
|
||||
help='Reset photo cache before generating.')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
reset = options['reset']
|
||||
sizes = options['sizes']
|
||||
|
||||
if not sizes:
|
||||
photosizes = PhotoSize.objects.all()
|
||||
else:
|
||||
photosizes = PhotoSize.objects.filter(name__in=sizes)
|
||||
|
||||
if not len(photosizes):
|
||||
raise CommandError('No photo sizes were found.')
|
||||
|
||||
print('Caching photos, this may take a while...')
|
||||
|
||||
for cls in ImageModel.__subclasses__():
|
||||
for photosize in photosizes:
|
||||
print('Cacheing %s size images' % photosize.name)
|
||||
for obj in cls.objects.all():
|
||||
if reset:
|
||||
obj.remove_size(photosize)
|
||||
obj.create_size(photosize)
|
||||
57
photologue/management/commands/plcreatesize.py
Normal file
57
photologue/management/commands/plcreatesize.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Based on https://github.com/richardbarran/django-photologue/
|
||||
# by Richard Barran, BSD-3 licensed
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from photologue.models import PhotoSize
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = ('Creates a new Photologue photo size interactively.')
|
||||
requires_model_validation = True
|
||||
can_import_settings = True
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('name',
|
||||
type=str,
|
||||
help='Name of the new photo size')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
create_photosize(options['name'])
|
||||
|
||||
|
||||
def get_response(msg, func=int, default=None):
|
||||
while True:
|
||||
resp = input(msg)
|
||||
if not resp and default is not None:
|
||||
return default
|
||||
try:
|
||||
return func(resp)
|
||||
except Exception:
|
||||
print('Invalid input.')
|
||||
|
||||
|
||||
def create_photosize(name, width=0, height=0, crop=False, pre_cache=False, increment_count=False):
|
||||
try:
|
||||
size = PhotoSize.objects.get(name=name)
|
||||
exists = True
|
||||
except PhotoSize.DoesNotExist:
|
||||
size = PhotoSize(name=name)
|
||||
exists = False
|
||||
if exists:
|
||||
msg = 'A "%s" photo size already exists. Do you want to replace it? (yes, no):' % name
|
||||
if not get_response(msg, lambda inp: inp == 'yes', False):
|
||||
return
|
||||
print('\nWe will now define the "%s" photo size:\n' % size)
|
||||
w = get_response('Width (in pixels):', lambda inp: int(inp), width)
|
||||
h = get_response('Height (in pixels):', lambda inp: int(inp), height)
|
||||
c = get_response('Crop to fit? (yes, no):', lambda inp: inp == 'yes', crop)
|
||||
p = get_response('Pre-cache? (yes, no):', lambda inp: inp == 'yes', pre_cache)
|
||||
i = get_response('Increment count? (yes, no):', lambda inp: inp == 'yes', increment_count)
|
||||
size.width = w
|
||||
size.height = h
|
||||
size.crop = c
|
||||
size.pre_cache = p
|
||||
size.increment_count = i
|
||||
size.save()
|
||||
print('\nA "%s" photo size has been created.\n' % name)
|
||||
return size
|
||||
34
photologue/management/commands/plflush.py
Normal file
34
photologue/management/commands/plflush.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Based on https://github.com/richardbarran/django-photologue/
|
||||
# by Richard Barran, BSD-3 licensed
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from photologue.models import ImageModel, PhotoSize
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Clears the Photologue cache for the given sizes.'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('sizes',
|
||||
nargs='*',
|
||||
type=str,
|
||||
help='Name of the photosize.')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
sizes = options['sizes']
|
||||
|
||||
if not sizes:
|
||||
photosizes = PhotoSize.objects.all()
|
||||
else:
|
||||
photosizes = PhotoSize.objects.filter(name__in=sizes)
|
||||
|
||||
if not len(photosizes):
|
||||
raise CommandError('No photo sizes were found.')
|
||||
|
||||
print('Flushing cache...')
|
||||
|
||||
for cls in ImageModel.__subclasses__():
|
||||
for photosize in photosizes:
|
||||
print('Flushing %s size images' % photosize.name)
|
||||
for obj in cls.objects.all():
|
||||
obj.remove_size(photosize)
|
||||
158
photologue/migrations/0001_initial.py
Normal file
158
photologue/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.core.validators
|
||||
import django.utils.timezone
|
||||
import sortedm2m.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
import photologue.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('sites', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Gallery',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
|
||||
('date_added', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date published')),
|
||||
('title', models.CharField(max_length=50, verbose_name='title', unique=True)),
|
||||
('slug', models.SlugField(help_text='A "slug" is a unique URL-friendly title for an object.', verbose_name='title slug', unique=True)),
|
||||
('description', models.TextField(blank=True, verbose_name='description')),
|
||||
('is_public', models.BooleanField(help_text='Public galleries will be displayed in the default views.', verbose_name='is public', default=True)),
|
||||
('tags', photologue.models.TagField(max_length=255, help_text='Django-tagging was not found, tags will be treated as plain text.', blank=True, verbose_name='tags')),
|
||||
('sites', models.ManyToManyField(blank=True, verbose_name='sites', null=True, to='sites.Site')),
|
||||
],
|
||||
options={
|
||||
'get_latest_by': 'date_added',
|
||||
'verbose_name': 'gallery',
|
||||
'ordering': ['-date_added'],
|
||||
'verbose_name_plural': 'galleries',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GalleryUpload',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
|
||||
('zip_file', models.FileField(help_text='Select a .zip file of images to upload into a new Gallery.', verbose_name='images file (.zip)', upload_to='photologue/temp')),
|
||||
('title', models.CharField(max_length=50, help_text='All uploaded photos will be given a title made up of this title + a sequential number.', verbose_name='title')),
|
||||
('caption', models.TextField(help_text='Caption will be added to all photos.', blank=True, verbose_name='caption')),
|
||||
('description', models.TextField(help_text='A description of this Gallery.', blank=True, verbose_name='description')),
|
||||
('is_public', models.BooleanField(help_text='Uncheck this to make the uploaded gallery and included photographs private.', verbose_name='is public', default=True)),
|
||||
('tags', models.CharField(max_length=255, help_text='Django-tagging was not found, tags will be treated as plain text.', blank=True, verbose_name='tags')),
|
||||
('gallery', models.ForeignKey(blank=True, verbose_name='gallery', null=True, help_text='Select a gallery to add these images to. Leave this empty to create a new gallery from the supplied title.', to='photologue.Gallery', on_delete=models.CASCADE)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'gallery upload',
|
||||
'verbose_name_plural': 'gallery uploads',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Photo',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
|
||||
('image', models.ImageField(upload_to=photologue.models.get_storage_path, verbose_name='image')),
|
||||
('date_taken', models.DateTimeField(verbose_name='date taken', blank=True, editable=False, null=True)),
|
||||
('view_count', models.PositiveIntegerField(verbose_name='view count', default=0, editable=False)),
|
||||
('crop_from', models.CharField(max_length=10, default='center', blank=True, verbose_name='crop from', choices=[('top', 'Top'), ('right', 'Right'), ('bottom', 'Bottom'), ('left', 'Left'), ('center', 'Center (Default)')])),
|
||||
('title', models.CharField(max_length=50, verbose_name='title', unique=True)),
|
||||
('slug', models.SlugField(help_text='A "slug" is a unique URL-friendly title for an object.', verbose_name='slug', unique=True)),
|
||||
('caption', models.TextField(blank=True, verbose_name='caption')),
|
||||
('date_added', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date added')),
|
||||
('is_public', models.BooleanField(help_text='Public photographs will be displayed in the default views.', verbose_name='is public', default=True)),
|
||||
('tags', photologue.models.TagField(max_length=255, help_text='Django-tagging was not found, tags will be treated as plain text.', blank=True, verbose_name='tags')),
|
||||
('sites', models.ManyToManyField(blank=True, verbose_name='sites', null=True, to='sites.Site')),
|
||||
],
|
||||
options={
|
||||
'get_latest_by': 'date_added',
|
||||
'verbose_name': 'photo',
|
||||
'ordering': ['-date_added'],
|
||||
'verbose_name_plural': 'photos',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='gallery',
|
||||
name='photos',
|
||||
field=sortedm2m.fields.SortedManyToManyField(blank=True, verbose_name='photos', null=True, to='photologue.Photo'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PhotoEffect',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
|
||||
('name', models.CharField(max_length=30, verbose_name='name', unique=True)),
|
||||
('description', models.TextField(blank=True, verbose_name='description')),
|
||||
('transpose_method', models.CharField(max_length=15, blank=True, verbose_name='rotate or flip', choices=[('FLIP_LEFT_RIGHT', 'Flip left to right'), ('FLIP_TOP_BOTTOM', 'Flip top to bottom'), ('ROTATE_90', 'Rotate 90 degrees counter-clockwise'), ('ROTATE_270', 'Rotate 90 degrees clockwise'), ('ROTATE_180', 'Rotate 180 degrees')])),
|
||||
('color', models.FloatField(help_text='A factor of 0.0 gives a black and white image, a factor of 1.0 gives the original image.', verbose_name='color', default=1.0)),
|
||||
('brightness', models.FloatField(help_text='A factor of 0.0 gives a black image, a factor of 1.0 gives the original image.', verbose_name='brightness', default=1.0)),
|
||||
('contrast', models.FloatField(help_text='A factor of 0.0 gives a solid grey image, a factor of 1.0 gives the original image.', verbose_name='contrast', default=1.0)),
|
||||
('sharpness', models.FloatField(help_text='A factor of 0.0 gives a blurred image, a factor of 1.0 gives the original image.', verbose_name='sharpness', default=1.0)),
|
||||
('filters', models.CharField(max_length=200, help_text='Chain multiple filters using the following pattern "FILTER_ONE->FILTER_TWO->FILTER_THREE". Image filters will be applied in order. The following filters are available: BLUR, CONTOUR, DETAIL, EDGE_ENHANCE, EDGE_ENHANCE_MORE, EMBOSS, FIND_EDGES, SHARPEN, SMOOTH, SMOOTH_MORE.', blank=True, verbose_name='filters')),
|
||||
('reflection_size', models.FloatField(help_text='The height of the reflection as a percentage of the orignal image. A factor of 0.0 adds no reflection, a factor of 1.0 adds a reflection equal to the height of the orignal image.', verbose_name='size', default=0)),
|
||||
('reflection_strength', models.FloatField(help_text='The initial opacity of the reflection gradient.', verbose_name='strength', default=0.6)),
|
||||
('background_color', models.CharField(max_length=7, help_text='The background color of the reflection gradient. Set this to match the background color of your page.', verbose_name='color', default='#FFFFFF')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'photo effect',
|
||||
'verbose_name_plural': 'photo effects',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='photo',
|
||||
name='effect',
|
||||
field=models.ForeignKey(blank=True, verbose_name='effect', null=True, to='photologue.PhotoEffect', on_delete=models.CASCADE),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PhotoSize',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
|
||||
('name', models.CharField(max_length=40, help_text='Photo size name should contain only letters, numbers and underscores. Examples: "thumbnail", "display", "small", "main_page_widget".', verbose_name='name', unique=True, validators=[django.core.validators.RegexValidator(regex='^[a-z0-9_]+$', message='Use only plain lowercase letters (ASCII), numbers and underscores.')])),
|
||||
('width', models.PositiveIntegerField(help_text='If width is set to "0" the image will be scaled to the supplied height.', verbose_name='width', default=0)),
|
||||
('height', models.PositiveIntegerField(help_text='If height is set to "0" the image will be scaled to the supplied width', verbose_name='height', default=0)),
|
||||
('quality', models.PositiveIntegerField(help_text='JPEG image quality.', verbose_name='quality', choices=[(30, 'Very Low'), (40, 'Low'), (50, 'Medium-Low'), (60, 'Medium'), (70, 'Medium-High'), (80, 'High'), (90, 'Very High')], default=70)),
|
||||
('upscale', models.BooleanField(help_text='If selected the image will be scaled up if necessary to fit the supplied dimensions. Cropped sizes will be upscaled regardless of this setting.', verbose_name='upscale images?', default=False)),
|
||||
('crop', models.BooleanField(help_text='If selected the image will be scaled and cropped to fit the supplied dimensions.', verbose_name='crop to fit?', default=False)),
|
||||
('pre_cache', models.BooleanField(help_text='If selected this photo size will be pre-cached as photos are added.', verbose_name='pre-cache?', default=False)),
|
||||
('increment_count', models.BooleanField(help_text='If selected the image\'s "view_count" will be incremented when this photo size is displayed.', verbose_name='increment view count?', default=False)),
|
||||
('effect', models.ForeignKey(blank=True, verbose_name='photo effect', null=True, to='photologue.PhotoEffect', on_delete=models.CASCADE)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'photo size',
|
||||
'ordering': ['width', 'height'],
|
||||
'verbose_name_plural': 'photo sizes',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Watermark',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
|
||||
('name', models.CharField(max_length=30, verbose_name='name', unique=True)),
|
||||
('description', models.TextField(blank=True, verbose_name='description')),
|
||||
('image', models.ImageField(upload_to='photologue/watermarks', verbose_name='image')),
|
||||
('style', models.CharField(max_length=5, default='scale', verbose_name='style', choices=[('tile', 'Tile'), ('scale', 'Scale')])),
|
||||
('opacity', models.FloatField(help_text='The opacity of the overlay.', verbose_name='opacity', default=1)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'watermark',
|
||||
'verbose_name_plural': 'watermarks',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='photosize',
|
||||
name='watermark',
|
||||
field=models.ForeignKey(blank=True, verbose_name='watermark image', null=True, to='photologue.Watermark', on_delete=models.CASCADE),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
||||
43
photologue/migrations/0002_photosize_data.py
Normal file
43
photologue/migrations/0002_photosize_data.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# encoding: utf8
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def initial_photosizes(apps, schema_editor):
|
||||
|
||||
PhotoSize = apps.get_model('photologue', 'PhotoSize')
|
||||
|
||||
# If there are already Photosizes, then we are upgrading an existing
|
||||
# installation, we don't want to auto-create some PhotoSizes.
|
||||
if PhotoSize.objects.all().count() > 0:
|
||||
return
|
||||
PhotoSize.objects.create(name='admin_thumbnail',
|
||||
width=100,
|
||||
height=75,
|
||||
crop=True,
|
||||
pre_cache=True,
|
||||
increment_count=False)
|
||||
PhotoSize.objects.create(name='thumbnail',
|
||||
width=100,
|
||||
height=75,
|
||||
crop=True,
|
||||
pre_cache=True,
|
||||
increment_count=False)
|
||||
PhotoSize.objects.create(name='display',
|
||||
width=400,
|
||||
crop=False,
|
||||
pre_cache=True,
|
||||
increment_count=True)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0001_initial'),
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(initial_photosizes),
|
||||
]
|
||||
19
photologue/migrations/0003_auto_20140822_1716.py
Normal file
19
photologue/migrations/0003_auto_20140822_1716.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0002_photosize_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='galleryupload',
|
||||
name='title',
|
||||
field=models.CharField(null=True, help_text='All uploaded photos will be given a title made up of this title + a sequential number.', max_length=50, verbose_name='title', blank=True),
|
||||
),
|
||||
]
|
||||
35
photologue/migrations/0004_auto_20140915_1259.py
Normal file
35
photologue/migrations/0004_auto_20140915_1259.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sortedm2m.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0003_auto_20140822_1716'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='gallery',
|
||||
name='photos',
|
||||
field=sortedm2m.fields.SortedManyToManyField(to='photologue.Photo', related_name='galleries', null=True, verbose_name='photos', blank=True, help_text=None),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='effect',
|
||||
field=models.ForeignKey(to='photologue.PhotoEffect', blank=True, related_name='photo_related', verbose_name='effect', null=True, on_delete=models.CASCADE),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photosize',
|
||||
name='effect',
|
||||
field=models.ForeignKey(to='photologue.PhotoEffect', blank=True, related_name='photo_sizes', verbose_name='photo effect', null=True, on_delete=models.CASCADE),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photosize',
|
||||
name='watermark',
|
||||
field=models.ForeignKey(to='photologue.Watermark', blank=True, related_name='photo_sizes', verbose_name='watermark image', null=True, on_delete=models.CASCADE),
|
||||
),
|
||||
]
|
||||
20
photologue/migrations/0005_auto_20141027_1552.py
Normal file
20
photologue/migrations/0005_auto_20141027_1552.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0004_auto_20140915_1259'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='title',
|
||||
field=models.CharField(unique=True, max_length=60, verbose_name='title'),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
||||
21
photologue/migrations/0006_auto_20141028_2005.py
Normal file
21
photologue/migrations/0006_auto_20141028_2005.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0005_auto_20141027_1552'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='galleryupload',
|
||||
name='gallery',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='GalleryUpload',
|
||||
),
|
||||
]
|
||||
30
photologue/migrations/0007_auto_20150404_1737.py
Normal file
30
photologue/migrations/0007_auto_20150404_1737.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sortedm2m.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0006_auto_20141028_2005'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='gallery',
|
||||
name='photos',
|
||||
field=sortedm2m.fields.SortedManyToManyField(help_text=None, related_name='galleries', verbose_name='photos', to='photologue.Photo', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='gallery',
|
||||
name='sites',
|
||||
field=models.ManyToManyField(to='sites.Site', verbose_name='sites', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='sites',
|
||||
field=models.ManyToManyField(to='sites.Site', verbose_name='sites', blank=True),
|
||||
),
|
||||
]
|
||||
22
photologue/migrations/0008_auto_20150509_1557.py
Normal file
22
photologue/migrations/0008_auto_20150509_1557.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0007_auto_20150404_1737'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='gallery',
|
||||
name='tags',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='photo',
|
||||
name='tags',
|
||||
),
|
||||
]
|
||||
20
photologue/migrations/0009_auto_20160102_0904.py
Normal file
20
photologue/migrations/0009_auto_20160102_0904.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9 on 2016-01-02 09:04
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0008_auto_20150509_1557'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='date_taken',
|
||||
field=models.DateTimeField(blank=True, help_text='Date image was taken; is obtained from the image EXIF data.', null=True, verbose_name='date taken'),
|
||||
),
|
||||
]
|
||||
35
photologue/migrations/0010_auto_20160105_1307.py
Normal file
35
photologue/migrations/0010_auto_20160105_1307.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9 on 2016-01-05 13:07
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0009_auto_20160102_0904'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='gallery',
|
||||
name='slug',
|
||||
field=models.SlugField(help_text='A "slug" is a unique URL-friendly title for an object.', max_length=250, unique=True, verbose_name='title slug'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='gallery',
|
||||
name='title',
|
||||
field=models.CharField(max_length=250, unique=True, verbose_name='title'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='slug',
|
||||
field=models.SlugField(help_text='A "slug" is a unique URL-friendly title for an object.', max_length=250, unique=True, verbose_name='slug'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='title',
|
||||
field=models.CharField(max_length=250, unique=True, verbose_name='title'),
|
||||
),
|
||||
]
|
||||
18
photologue/migrations/0011_auto_20190223_2138.py
Normal file
18
photologue/migrations/0011_auto_20190223_2138.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.1.7 on 2019-02-23 21:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0010_auto_20160105_1307'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photoeffect',
|
||||
name='filters',
|
||||
field=models.CharField(blank=True, help_text='Chain multiple filters using the following pattern "FILTER_ONE->FILTER_TWO->FILTER_THREE". Image filters will be applied in order. The following filters are available: BLUR, CONTOUR, DETAIL, EDGE_ENHANCE, EDGE_ENHANCE_MORE, EMBOSS, FIND_EDGES, Kernel, SHARPEN, SMOOTH, SMOOTH_MORE.', max_length=200, verbose_name='filters'),
|
||||
),
|
||||
]
|
||||
39
photologue/migrations/0012_auto_20220129_2207.py
Normal file
39
photologue/migrations/0012_auto_20220129_2207.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Generated by Django 3.2.11 on 2022-01-29 22:07
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0011_auto_20190223_2138'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='gallery',
|
||||
name='sites',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='photo',
|
||||
name='effect',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='photo',
|
||||
name='sites',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='photosize',
|
||||
name='effect',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='photosize',
|
||||
name='watermark',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='PhotoEffect',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Watermark',
|
||||
),
|
||||
]
|
||||
18
photologue/migrations/0013_alter_gallery_photos.py
Normal file
18
photologue/migrations/0013_alter_gallery_photos.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.11 on 2022-01-30 07:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('photologue', '0012_auto_20220129_2207'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='gallery',
|
||||
name='photos',
|
||||
field=models.ManyToManyField(blank=True, related_name='galleries', to='photologue.Photo', verbose_name='photos'),
|
||||
),
|
||||
]
|
||||
0
photologue/migrations/__init__.py
Normal file
0
photologue/migrations/__init__.py
Normal file
659
photologue/models.py
Normal file
659
photologue/models.py
Normal file
|
|
@ -0,0 +1,659 @@
|
|||
# Based on https://github.com/richardbarran/django-photologue/
|
||||
# by Richard Barran, BSD-3 licensed
|
||||
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import unicodedata
|
||||
from datetime import datetime
|
||||
from functools import partial
|
||||
from importlib import import_module
|
||||
from inspect import isclass
|
||||
from io import BytesIO
|
||||
|
||||
import exifread
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.files.storage import default_storage
|
||||
from django.core.validators import RegexValidator
|
||||
from django.db import models
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import filepath_to_uri, force_str, smart_str
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from PIL import Image, ImageFile, ImageFilter
|
||||
|
||||
logger = logging.getLogger('photologue.models')
|
||||
|
||||
# Default limit for gallery.latest
|
||||
LATEST_LIMIT = getattr(settings, 'PHOTOLOGUE_GALLERY_LATEST_LIMIT', None)
|
||||
|
||||
# max_length setting for the ImageModel ImageField
|
||||
IMAGE_FIELD_MAX_LENGTH = getattr(settings, 'PHOTOLOGUE_IMAGE_FIELD_MAX_LENGTH', 100)
|
||||
|
||||
# Modify image file buffer size.
|
||||
ImageFile.MAXBLOCK = getattr(settings, 'PHOTOLOGUE_MAXBLOCK', 256 * 2 ** 10)
|
||||
|
||||
# Look for user function to define file paths
|
||||
PHOTOLOGUE_PATH = getattr(settings, 'PHOTOLOGUE_PATH', None)
|
||||
if PHOTOLOGUE_PATH is not None:
|
||||
if callable(PHOTOLOGUE_PATH):
|
||||
get_storage_path = PHOTOLOGUE_PATH
|
||||
else:
|
||||
parts = PHOTOLOGUE_PATH.split('.')
|
||||
module_name = '.'.join(parts[:-1])
|
||||
module = import_module(module_name)
|
||||
get_storage_path = getattr(module, parts[-1])
|
||||
else:
|
||||
def get_storage_path(instance, filename):
|
||||
fn = unicodedata.normalize('NFKD', force_str(filename)).encode('ascii', 'ignore').decode('ascii')
|
||||
return os.path.join('photos', fn)
|
||||
|
||||
# Support CACHEDIR.TAG spec for backups for ignoring cache dir.
|
||||
# See http://www.brynosaurus.com/cachedir/spec.html
|
||||
PHOTOLOGUE_CACHEDIRTAG = os.path.join("photos", "cache", "CACHEDIR.TAG")
|
||||
if not default_storage.exists(PHOTOLOGUE_CACHEDIRTAG):
|
||||
default_storage.save(PHOTOLOGUE_CACHEDIRTAG, ContentFile(
|
||||
b"Signature: 8a477f597d28d172789f06886806bc55"))
|
||||
|
||||
# Exif Orientation values
|
||||
# Value 0thRow 0thColumn
|
||||
# 1 top left
|
||||
# 2 top right
|
||||
# 3 bottom right
|
||||
# 4 bottom left
|
||||
# 5 left top
|
||||
# 6 right top
|
||||
# 7 right bottom
|
||||
# 8 left bottom
|
||||
|
||||
# Image Orientations (according to EXIF informations) that needs to be
|
||||
# transposed and appropriate action
|
||||
IMAGE_EXIF_ORIENTATION_MAP = {
|
||||
2: Image.FLIP_LEFT_RIGHT,
|
||||
3: Image.ROTATE_180,
|
||||
6: Image.ROTATE_270,
|
||||
8: Image.ROTATE_90,
|
||||
}
|
||||
|
||||
# Quality options for JPEG images
|
||||
JPEG_QUALITY_CHOICES = (
|
||||
(30, _('Very Low')),
|
||||
(40, _('Low')),
|
||||
(50, _('Medium-Low')),
|
||||
(60, _('Medium')),
|
||||
(70, _('Medium-High')),
|
||||
(80, _('High')),
|
||||
(90, _('Very High')),
|
||||
)
|
||||
|
||||
# choices for new crop_anchor field in Photo
|
||||
CROP_ANCHOR_CHOICES = (
|
||||
('top', _('Top')),
|
||||
('right', _('Right')),
|
||||
('bottom', _('Bottom')),
|
||||
('left', _('Left')),
|
||||
('center', _('Center (Default)')),
|
||||
)
|
||||
|
||||
IMAGE_TRANSPOSE_CHOICES = (
|
||||
('FLIP_LEFT_RIGHT', _('Flip left to right')),
|
||||
('FLIP_TOP_BOTTOM', _('Flip top to bottom')),
|
||||
('ROTATE_90', _('Rotate 90 degrees counter-clockwise')),
|
||||
('ROTATE_270', _('Rotate 90 degrees clockwise')),
|
||||
('ROTATE_180', _('Rotate 180 degrees')),
|
||||
)
|
||||
|
||||
# Prepare a list of image filters
|
||||
filter_names = []
|
||||
for n in dir(ImageFilter):
|
||||
klass = getattr(ImageFilter, n)
|
||||
if isclass(klass) and issubclass(klass, ImageFilter.BuiltinFilter) and \
|
||||
hasattr(klass, 'name'):
|
||||
filter_names.append(klass.__name__)
|
||||
IMAGE_FILTERS_HELP_TEXT = _('Chain multiple filters using the following pattern "FILTER_ONE->FILTER_TWO->FILTER_THREE"'
|
||||
'. Image filters will be applied in order. The following filters are available: %s.'
|
||||
% (', '.join(filter_names)))
|
||||
|
||||
size_method_map = {}
|
||||
|
||||
|
||||
class TagField(models.CharField):
|
||||
"""Tags have been removed from Photologue, but the migrations still refer to them so this
|
||||
Tagfield definition is left here.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
default_kwargs = {'max_length': 255, 'blank': True}
|
||||
default_kwargs.update(kwargs)
|
||||
super().__init__(**default_kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
return 'CharField'
|
||||
|
||||
|
||||
class Gallery(models.Model):
|
||||
date_added = models.DateTimeField(_('date published'),
|
||||
default=now)
|
||||
title = models.CharField(_('title'),
|
||||
max_length=250,
|
||||
unique=True)
|
||||
slug = models.SlugField(_('title slug'),
|
||||
unique=True,
|
||||
max_length=250,
|
||||
help_text=_('A "slug" is a unique URL-friendly title for an object.'))
|
||||
description = models.TextField(_('description'),
|
||||
blank=True)
|
||||
is_public = models.BooleanField(_('is public'),
|
||||
default=True,
|
||||
help_text=_('Public galleries will be displayed '
|
||||
'in the default views.'))
|
||||
photos = models.ManyToManyField('photologue.Photo',
|
||||
related_name='galleries',
|
||||
verbose_name=_('photos'),
|
||||
blank=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-date_added']
|
||||
get_latest_by = 'date_added'
|
||||
verbose_name = _('gallery')
|
||||
verbose_name_plural = _('galleries')
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('photologue:pl-gallery', args=[self.slug])
|
||||
|
||||
def latest(self, limit=LATEST_LIMIT, public=True):
|
||||
if not limit:
|
||||
limit = self.photo_count()
|
||||
if public:
|
||||
return self.public()[:limit]
|
||||
else:
|
||||
return self.photos[:limit]
|
||||
|
||||
def sample(self, count=None, public=True):
|
||||
"""Return a sample of photos, ordered at random."""
|
||||
if not count:
|
||||
count = 1
|
||||
if count > self.photo_count():
|
||||
count = self.photo_count()
|
||||
if public:
|
||||
photo_set = self.public()
|
||||
else:
|
||||
photo_set = self.photos
|
||||
return random.sample(set(photo_set), count)
|
||||
|
||||
def photo_count(self, public=True):
|
||||
"""Return a count of all the photos in this gallery."""
|
||||
if public:
|
||||
return self.public().count()
|
||||
else:
|
||||
return self.photos.count()
|
||||
|
||||
photo_count.short_description = _('count')
|
||||
|
||||
def public(self):
|
||||
"""Return a queryset of all the public photos in this gallery."""
|
||||
return self.photos.filter(is_public=True)
|
||||
|
||||
|
||||
class ImageModel(models.Model):
|
||||
image = models.ImageField(_('image'),
|
||||
max_length=IMAGE_FIELD_MAX_LENGTH,
|
||||
upload_to=get_storage_path)
|
||||
date_taken = models.DateTimeField(_('date taken'),
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text=_('Date image was taken; is obtained from the image EXIF data.'))
|
||||
view_count = models.PositiveIntegerField(_('view count'),
|
||||
default=0,
|
||||
editable=False)
|
||||
crop_from = models.CharField(_('crop from'),
|
||||
blank=True,
|
||||
max_length=10,
|
||||
default='center',
|
||||
choices=CROP_ANCHOR_CHOICES)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def exif(self, file=None):
|
||||
try:
|
||||
if file:
|
||||
tags = exifread.process_file(file)
|
||||
else:
|
||||
with self.image.storage.open(self.image.name, 'rb') as file:
|
||||
tags = exifread.process_file(file, details=False)
|
||||
return tags
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
def admin_thumbnail(self):
|
||||
func = getattr(self, 'get_admin_thumbnail_url', None)
|
||||
if func is None:
|
||||
return _('An "admin_thumbnail" photo size has not been defined.')
|
||||
else:
|
||||
if hasattr(self, 'get_absolute_url'):
|
||||
return mark_safe('<a href="{}"><img src="{}"></a>'.format(self.get_absolute_url(), func()))
|
||||
else:
|
||||
return mark_safe('<a href="{}"><img src="{}"></a>'.format(self.image.url, func()))
|
||||
|
||||
admin_thumbnail.short_description = _('Thumbnail')
|
||||
admin_thumbnail.allow_tags = True
|
||||
|
||||
def cache_path(self):
|
||||
return os.path.join(os.path.dirname(self.image.name), "cache")
|
||||
|
||||
def cache_url(self):
|
||||
return '/'.join([os.path.dirname(self.image.url), "cache"])
|
||||
|
||||
def image_filename(self):
|
||||
return os.path.basename(force_str(self.image.name))
|
||||
|
||||
def _get_filename_for_size(self, size):
|
||||
size = getattr(size, 'name', size)
|
||||
base, ext = os.path.splitext(self.image_filename())
|
||||
return ''.join([base, '_', size, ext])
|
||||
|
||||
def _get_size_photosize(self, size):
|
||||
return PhotoSizeCache().sizes.get(size)
|
||||
|
||||
def _get_size_size(self, size):
|
||||
photosize = PhotoSizeCache().sizes.get(size)
|
||||
if not self.size_exists(photosize):
|
||||
self.create_size(photosize)
|
||||
try:
|
||||
return Image.open(self.image.storage.open(
|
||||
self._get_size_filename(size))).size
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _get_size_url(self, size):
|
||||
photosize = PhotoSizeCache().sizes.get(size)
|
||||
if not self.size_exists(photosize):
|
||||
self.create_size(photosize)
|
||||
if photosize.increment_count:
|
||||
self.increment_count()
|
||||
return '/'.join([
|
||||
self.cache_url(),
|
||||
filepath_to_uri(self._get_filename_for_size(photosize.name))])
|
||||
|
||||
def _get_size_filename(self, size):
|
||||
photosize = PhotoSizeCache().sizes.get(size)
|
||||
return smart_str(os.path.join(self.cache_path(),
|
||||
self._get_filename_for_size(photosize.name)))
|
||||
|
||||
def increment_count(self):
|
||||
self.view_count += 1
|
||||
models.Model.save(self)
|
||||
|
||||
def __getattr__(self, name):
|
||||
global size_method_map
|
||||
if not size_method_map:
|
||||
init_size_method_map()
|
||||
di = size_method_map.get(name, None)
|
||||
if di is not None:
|
||||
result = partial(getattr(self, di['base_name']), di['size'])
|
||||
setattr(self, name, result)
|
||||
return result
|
||||
else:
|
||||
raise AttributeError
|
||||
|
||||
def size_exists(self, photosize):
|
||||
func = getattr(self, "get_%s_filename" % photosize.name, None)
|
||||
if func is not None:
|
||||
if self.image.storage.exists(func()):
|
||||
return True
|
||||
return False
|
||||
|
||||
def resize_image(self, im, photosize):
|
||||
cur_width, cur_height = im.size
|
||||
new_width, new_height = photosize.size
|
||||
if photosize.crop:
|
||||
ratio = max(float(new_width) / cur_width, float(new_height) / cur_height)
|
||||
x = (cur_width * ratio)
|
||||
y = (cur_height * ratio)
|
||||
xd = abs(new_width - x)
|
||||
yd = abs(new_height - y)
|
||||
x_diff = int(xd / 2)
|
||||
y_diff = int(yd / 2)
|
||||
if self.crop_from == 'top':
|
||||
box = (int(x_diff), 0, int(x_diff + new_width), new_height)
|
||||
elif self.crop_from == 'left':
|
||||
box = (0, int(y_diff), new_width, int(y_diff + new_height))
|
||||
elif self.crop_from == 'bottom':
|
||||
# y - yd = new_height
|
||||
box = (int(x_diff), int(yd), int(x_diff + new_width), int(y))
|
||||
elif self.crop_from == 'right':
|
||||
# x - xd = new_width
|
||||
box = (int(xd), int(y_diff), int(x), int(y_diff + new_height))
|
||||
else:
|
||||
box = (int(x_diff), int(y_diff), int(x_diff + new_width), int(y_diff + new_height))
|
||||
im = im.resize((int(x), int(y)), Image.ANTIALIAS).crop(box)
|
||||
else:
|
||||
if not new_width == 0 and not new_height == 0:
|
||||
ratio = min(float(new_width) / cur_width,
|
||||
float(new_height) / cur_height)
|
||||
else:
|
||||
if new_width == 0:
|
||||
ratio = float(new_height) / cur_height
|
||||
else:
|
||||
ratio = float(new_width) / cur_width
|
||||
new_dimensions = (int(round(cur_width * ratio)),
|
||||
int(round(cur_height * ratio)))
|
||||
if new_dimensions[0] > cur_width or \
|
||||
new_dimensions[1] > cur_height:
|
||||
if not photosize.upscale:
|
||||
return im
|
||||
im = im.resize(new_dimensions, Image.ANTIALIAS)
|
||||
return im
|
||||
|
||||
def create_size(self, photosize, recreate=False):
|
||||
if self.size_exists(photosize) and not recreate:
|
||||
return
|
||||
try:
|
||||
im = Image.open(self.image.storage.open(self.image.name))
|
||||
except OSError:
|
||||
return
|
||||
# Save the original format
|
||||
im_format = im.format
|
||||
# Apply effect if found
|
||||
if self.effect is not None:
|
||||
im = self.effect.pre_process(im)
|
||||
elif photosize.effect is not None:
|
||||
im = photosize.effect.pre_process(im)
|
||||
# Rotate if found & necessary
|
||||
if 'Image Orientation' in self.exif() and \
|
||||
self.exif().get('Image Orientation').values[0] in IMAGE_EXIF_ORIENTATION_MAP:
|
||||
im = im.transpose(
|
||||
IMAGE_EXIF_ORIENTATION_MAP[self.EXIF().get('Image Orientation').values[0]])
|
||||
# Resize/crop image
|
||||
if (im.size != photosize.size and photosize.size != (0, 0)) or recreate:
|
||||
im = self.resize_image(im, photosize)
|
||||
# Apply effect if found
|
||||
if self.effect is not None:
|
||||
im = self.effect.post_process(im)
|
||||
elif photosize.effect is not None:
|
||||
im = photosize.effect.post_process(im)
|
||||
# Save file
|
||||
im_filename = getattr(self, "get_%s_filename" % photosize.name)()
|
||||
try:
|
||||
buffer = BytesIO()
|
||||
if im_format != 'JPEG':
|
||||
im.save(buffer, im_format)
|
||||
else:
|
||||
# Issue #182 - test fix from https://github.com/bashu/django-watermark/issues/31
|
||||
if im.mode.endswith('A'):
|
||||
im = im.convert(im.mode[:-1])
|
||||
im.save(buffer, 'JPEG', quality=int(photosize.quality),
|
||||
optimize=True)
|
||||
buffer_contents = ContentFile(buffer.getvalue())
|
||||
self.image.storage.save(im_filename, buffer_contents)
|
||||
except OSError as e:
|
||||
if self.image.storage.exists(im_filename):
|
||||
self.image.storage.delete(im_filename)
|
||||
raise e
|
||||
|
||||
def remove_size(self, photosize, remove_dirs=True):
|
||||
if not self.size_exists(photosize):
|
||||
return
|
||||
filename = getattr(self, "get_%s_filename" % photosize.name)()
|
||||
if self.image.storage.exists(filename):
|
||||
self.image.storage.delete(filename)
|
||||
|
||||
def clear_cache(self):
|
||||
cache = PhotoSizeCache()
|
||||
for photosize in cache.sizes.values():
|
||||
self.remove_size(photosize, False)
|
||||
|
||||
def pre_cache(self, recreate=False):
|
||||
cache = PhotoSizeCache()
|
||||
if recreate:
|
||||
self.clear_cache()
|
||||
for photosize in cache.sizes.values():
|
||||
if photosize.pre_cache:
|
||||
self.create_size(photosize, recreate)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._old_image = self.image
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
recreate = kwargs.pop('recreate', False)
|
||||
image_has_changed = False
|
||||
if self._get_pk_val() and (self._old_image != self.image):
|
||||
image_has_changed = True
|
||||
# If we have changed the image, we need to clear from the cache all instances of the old
|
||||
# image; clear_cache() works on the current (new) image, and in turn calls several other methods.
|
||||
# Changing them all to act on the old image was a lot of changes, so instead we temporarily swap old
|
||||
# and new images.
|
||||
new_image = self.image
|
||||
self.image = self._old_image
|
||||
self.clear_cache()
|
||||
self.image = new_image # Back to the new image.
|
||||
self._old_image.storage.delete(self._old_image.name) # Delete (old) base image.
|
||||
if self.date_taken is None or image_has_changed:
|
||||
# Attempt to get the date the photo was taken from the EXIF data.
|
||||
try:
|
||||
exif_date = self.exif(self.image.file).get('EXIF DateTimeOriginal', None)
|
||||
if exif_date is not None:
|
||||
d, t = exif_date.values.split()
|
||||
year, month, day = d.split(':')
|
||||
hour, minute, second = t.split(':')
|
||||
self.date_taken = datetime(int(year), int(month), int(day),
|
||||
int(hour), int(minute), int(second))
|
||||
except Exception:
|
||||
logger.error('Failed to read EXIF DateTimeOriginal', exc_info=True)
|
||||
super().save(*args, **kwargs)
|
||||
self.pre_cache(recreate)
|
||||
|
||||
def delete(self):
|
||||
assert self._get_pk_val() is not None, \
|
||||
"%s object can't be deleted because its %s attribute is set to None." % \
|
||||
(self._meta.object_name, self._meta.pk.attname)
|
||||
self.clear_cache()
|
||||
# Files associated to a FileField have to be manually deleted:
|
||||
# https://docs.djangoproject.com/en/dev/releases/1.3/#deleting-a-model-doesn-t-delete-associated-files
|
||||
# http://haineault.com/blog/147/
|
||||
# The data loss scenarios mentioned in the docs hopefully do not apply
|
||||
# to Photologue!
|
||||
super().delete()
|
||||
self.image.storage.delete(self.image.name)
|
||||
|
||||
|
||||
class Photo(ImageModel):
|
||||
title = models.CharField(_('title'),
|
||||
max_length=250,
|
||||
unique=True)
|
||||
slug = models.SlugField(_('slug'),
|
||||
unique=True,
|
||||
max_length=250,
|
||||
help_text=_('A "slug" is a unique URL-friendly title for an object.'))
|
||||
caption = models.TextField(_('caption'),
|
||||
blank=True)
|
||||
date_added = models.DateTimeField(_('date added'),
|
||||
default=now)
|
||||
is_public = models.BooleanField(_('is public'),
|
||||
default=True,
|
||||
help_text=_('Public photographs will be displayed in the default views.'))
|
||||
|
||||
class Meta:
|
||||
ordering = ['-date_added']
|
||||
get_latest_by = 'date_added'
|
||||
verbose_name = _("photo")
|
||||
verbose_name_plural = _("photos")
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# If crop_from or effect property has been changed on existing image,
|
||||
# update kwargs to force image recreation in parent class
|
||||
current = Photo.objects.get(pk=self.pk) if self.pk else None
|
||||
if current and (current.crop_from != self.crop_from or current.effect != self.effect):
|
||||
kwargs.update(recreate=True)
|
||||
|
||||
if self.slug is None:
|
||||
self.slug = slugify(self.title)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('photologue:pl-photo', args=[self.slug])
|
||||
|
||||
def public_galleries(self):
|
||||
"""Return the public galleries to which this photo belongs."""
|
||||
return self.galleries.filter(is_public=True)
|
||||
|
||||
def get_previous_in_gallery(self, gallery):
|
||||
"""Find the neighbour of this photo in the supplied gallery.
|
||||
We assume that the gallery and all its photos are on the same site.
|
||||
"""
|
||||
if not self.is_public:
|
||||
raise ValueError('Cannot determine neighbours of a non-public photo.')
|
||||
photos = gallery.photos.filter(is_public=True)
|
||||
if self not in photos:
|
||||
raise ValueError('Photo does not belong to gallery.')
|
||||
previous = None
|
||||
for photo in photos:
|
||||
if photo == self:
|
||||
return previous
|
||||
previous = photo
|
||||
|
||||
def get_next_in_gallery(self, gallery):
|
||||
"""Find the neighbour of this photo in the supplied gallery.
|
||||
We assume that the gallery and all its photos are on the same site.
|
||||
"""
|
||||
if not self.is_public:
|
||||
raise ValueError('Cannot determine neighbours of a non-public photo.')
|
||||
photos = gallery.photos.filter(is_public=True)
|
||||
if self not in photos:
|
||||
raise ValueError('Photo does not belong to gallery.')
|
||||
matched = False
|
||||
for photo in photos:
|
||||
if matched:
|
||||
return photo
|
||||
if photo == self:
|
||||
matched = True
|
||||
return None
|
||||
|
||||
|
||||
class PhotoSize(models.Model):
|
||||
"""About the Photosize name: it's used to create get_PHOTOSIZE_url() methods,
|
||||
so the name has to follow the same restrictions as any Python method name,
|
||||
e.g. no spaces or non-ascii characters."""
|
||||
|
||||
name = models.CharField(_('name'),
|
||||
max_length=40,
|
||||
unique=True,
|
||||
help_text=_(
|
||||
'Photo size name should contain only letters, numbers and underscores. Examples: '
|
||||
'"thumbnail", "display", "small", "main_page_widget".'),
|
||||
validators=[RegexValidator(regex='^[a-z0-9_]+$',
|
||||
message='Use only plain lowercase letters (ASCII), numbers and '
|
||||
'underscores.'
|
||||
)]
|
||||
)
|
||||
width = models.PositiveIntegerField(_('width'),
|
||||
default=0,
|
||||
help_text=_(
|
||||
'If width is set to "0" the image will be scaled to the supplied height.'))
|
||||
height = models.PositiveIntegerField(_('height'),
|
||||
default=0,
|
||||
help_text=_(
|
||||
'If height is set to "0" the image will be scaled to the supplied width'))
|
||||
quality = models.PositiveIntegerField(_('quality'),
|
||||
choices=JPEG_QUALITY_CHOICES,
|
||||
default=70,
|
||||
help_text=_('JPEG image quality.'))
|
||||
upscale = models.BooleanField(_('upscale images?'),
|
||||
default=False,
|
||||
help_text=_('If selected the image will be scaled up if necessary to fit the '
|
||||
'supplied dimensions. Cropped sizes will be upscaled regardless of this '
|
||||
'setting.')
|
||||
)
|
||||
crop = models.BooleanField(_('crop to fit?'),
|
||||
default=False,
|
||||
help_text=_('If selected the image will be scaled and cropped to fit the supplied '
|
||||
'dimensions.'))
|
||||
pre_cache = models.BooleanField(_('pre-cache?'),
|
||||
default=False,
|
||||
help_text=_('If selected this photo size will be pre-cached as photos are added.'))
|
||||
increment_count = models.BooleanField(_('increment view count?'),
|
||||
default=False,
|
||||
help_text=_('If selected the image\'s "view_count" will be incremented when '
|
||||
'this photo size is displayed.'))
|
||||
|
||||
class Meta:
|
||||
ordering = ['width', 'height']
|
||||
verbose_name = _('photo size')
|
||||
verbose_name_plural = _('photo sizes')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def clear_cache(self):
|
||||
for cls in ImageModel.__subclasses__():
|
||||
for obj in cls.objects.all():
|
||||
obj.remove_size(self)
|
||||
if self.pre_cache:
|
||||
obj.create_size(self)
|
||||
PhotoSizeCache().reset()
|
||||
|
||||
def clean(self):
|
||||
if self.crop is True:
|
||||
if self.width == 0 or self.height == 0:
|
||||
raise ValidationError(
|
||||
_("Can only crop photos if both width and height dimensions are set."))
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
PhotoSizeCache().reset()
|
||||
self.clear_cache()
|
||||
|
||||
def delete(self):
|
||||
assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." \
|
||||
% (self._meta.object_name, self._meta.pk.attname)
|
||||
self.clear_cache()
|
||||
super().delete()
|
||||
|
||||
def _get_size(self):
|
||||
return (self.width, self.height)
|
||||
|
||||
def _set_size(self, value):
|
||||
self.width, self.height = value
|
||||
|
||||
size = property(_get_size, _set_size)
|
||||
|
||||
|
||||
class PhotoSizeCache:
|
||||
__state = {"sizes": {}}
|
||||
|
||||
def __init__(self):
|
||||
self.__dict__ = self.__state
|
||||
if not len(self.sizes):
|
||||
sizes = PhotoSize.objects.all()
|
||||
for size in sizes:
|
||||
self.sizes[size.name] = size
|
||||
|
||||
def reset(self):
|
||||
global size_method_map
|
||||
size_method_map = {}
|
||||
self.sizes = {}
|
||||
|
||||
|
||||
def init_size_method_map():
|
||||
global size_method_map
|
||||
for size in PhotoSizeCache().sizes.keys():
|
||||
size_method_map['get_%s_size' % size] = \
|
||||
{'base_name': '_get_size_size', 'size': size}
|
||||
size_method_map['get_%s_photosize' % size] = \
|
||||
{'base_name': '_get_size_photosize', 'size': size}
|
||||
size_method_map['get_%s_url' % size] = \
|
||||
{'base_name': '_get_size_url', 'size': size}
|
||||
size_method_map['get_%s_filename' % size] = \
|
||||
{'base_name': '_get_size_filename', 'size': size}
|
||||
24
photologue/views.py
Normal file
24
photologue/views.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.views.generic.dates import ArchiveIndexView, YearArchiveView
|
||||
from django.views.generic.detail import DetailView
|
||||
|
||||
from .models import Gallery, Photo
|
||||
|
||||
|
||||
class GalleryDateView(LoginRequiredMixin):
|
||||
queryset = Gallery.objects.filter(is_public=True)
|
||||
date_field = 'extended__date_start'
|
||||
uses_datetime_field = False # Fix related object access
|
||||
allow_empty = True
|
||||
|
||||
|
||||
class GalleryArchiveIndexView(GalleryDateView, ArchiveIndexView):
|
||||
pass
|
||||
|
||||
|
||||
class GalleryYearArchiveView(GalleryDateView, YearArchiveView):
|
||||
make_object_list = True
|
||||
|
||||
|
||||
class PhotoDetailView(LoginRequiredMixin, DetailView):
|
||||
queryset = Photo.objects.filter(is_public=True)
|
||||
|
|
@ -2,7 +2,7 @@ from django.contrib import admin
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from photologue.admin import GalleryAdmin as GalleryAdminDefault
|
||||
from photologue.admin import PhotoAdmin as PhotoAdminDefault
|
||||
from photologue.models import Gallery, Photo, PhotoEffect, PhotoSize, Watermark
|
||||
from photologue.models import Gallery, Photo
|
||||
|
||||
from .models import GalleryExtended, PhotoExtended
|
||||
|
||||
|
|
@ -18,8 +18,6 @@ class GalleryAdmin(GalleryAdminDefault):
|
|||
model.
|
||||
"""
|
||||
inlines = [GalleryExtendedInline, ]
|
||||
autocomplete_fields = ['photos', ]
|
||||
search_fields = ['title', ]
|
||||
|
||||
|
||||
class PhotoExtendedInline(admin.StackedInline):
|
||||
|
|
@ -45,10 +43,5 @@ class PhotoAdmin(PhotoAdminDefault):
|
|||
get_owner.short_description = _('owner')
|
||||
|
||||
|
||||
admin.site.unregister(Gallery)
|
||||
admin.site.unregister(Photo)
|
||||
admin.site.unregister(PhotoEffect)
|
||||
admin.site.unregister(PhotoSize)
|
||||
admin.site.unregister(Watermark)
|
||||
admin.site.register(Gallery, GalleryAdmin)
|
||||
admin.site.register(Photo, PhotoAdmin)
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ from django.apps import AppConfig
|
|||
|
||||
|
||||
class PhotologueCustomConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.AutoField'
|
||||
name = 'photologue_custom'
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='owner')),
|
||||
('photo', models.OneToOneField(on_delete='cascade', related_name='extented', to='photologue.Photo')),
|
||||
('photo', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='extented', to='photologue.Photo')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Extra fields',
|
||||
|
|
@ -33,7 +33,7 @@ class Migration(migrations.Migration):
|
|||
name='GalleryExtended',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('gallery', models.OneToOneField(on_delete='cascade', related_name='extended', to='photologue.Gallery')),
|
||||
('gallery', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='extended', to='photologue.Gallery')),
|
||||
('tags', taggit.managers.TaggableManager(blank=True, help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')),
|
||||
],
|
||||
options={
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "photologue/root.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% endcomment %}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "photologue/root.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% endcomment %}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "photologue/root.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% endcomment %}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "photologue/root.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% endcomment %}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
from django.urls import path, re_path
|
||||
from photologue.views import GalleryArchiveIndexView, GalleryYearArchiveView, PhotoDetailView
|
||||
|
||||
from .views import (CustomGalleryArchiveIndexView, CustomGalleryDetailView,
|
||||
CustomGalleryYearArchiveView, CustomPhotoDetailView,
|
||||
GalleryDownload, GalleryUpload, TagDetail)
|
||||
from .views import CustomGalleryDetailView, GalleryDownload, GalleryUpload, TagDetail
|
||||
|
||||
# Rather than using photologue default router, we redefine our own router
|
||||
# with login and permission checks.
|
||||
app_name = 'photologue'
|
||||
urlpatterns = [
|
||||
path('tag/<slug:slug>/', TagDetail.as_view(), name='tag-detail'),
|
||||
path('gallery/', CustomGalleryArchiveIndexView.as_view(), name='pl-gallery-archive'),
|
||||
re_path(r'^gallery/(?P<year>\d{4})/$', CustomGalleryYearArchiveView.as_view(), name='pl-gallery-archive-year'),
|
||||
path('gallery/', GalleryArchiveIndexView.as_view(), name='pl-gallery-archive'),
|
||||
re_path(r'^gallery/(?P<year>\d{4})/$', GalleryYearArchiveView.as_view(), name='pl-gallery-archive-year'),
|
||||
path('gallery/<slug:slug>/', CustomGalleryDetailView.as_view(), name='pl-gallery'),
|
||||
path('gallery/<slug:slug>/<int:owner>/', CustomGalleryDetailView.as_view(), name='pl-gallery-owner'),
|
||||
path('gallery/<slug:slug>/download/', GalleryDownload.as_view(), name='pl-gallery-download'),
|
||||
path('photo/<slug:slug>/', CustomPhotoDetailView.as_view(), name='pl-photo'),
|
||||
path('photo/<slug:slug>/', PhotoDetailView.as_view(), name='pl-photo'),
|
||||
path('upload/', GalleryUpload.as_view(), name='pl-gallery-upload'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ from django.utils.text import slugify
|
|||
from django.views.generic.detail import DetailView
|
||||
from django.views.generic.edit import FormView
|
||||
from photologue.models import Gallery, Photo
|
||||
from photologue.views import (GalleryArchiveIndexView, GalleryYearArchiveView,
|
||||
PhotoDetailView)
|
||||
from PIL import Image
|
||||
from taggit.models import Tag
|
||||
|
||||
|
|
@ -35,33 +33,17 @@ class TagDetail(LoginRequiredMixin, DetailView):
|
|||
"""
|
||||
current_tag = self.get_object().slug
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['galleries'] = Gallery.objects.on_site().is_public() \
|
||||
context['galleries'] = Gallery.objects.filter(is_public=True) \
|
||||
.filter(extended__tags__slug=current_tag) \
|
||||
.order_by('-extended__date_start')
|
||||
return context
|
||||
|
||||
|
||||
class CustomGalleryArchiveIndexView(LoginRequiredMixin, GalleryArchiveIndexView):
|
||||
"""
|
||||
Override to use event date
|
||||
"""
|
||||
date_field = 'extended__date_start'
|
||||
uses_datetime_field = False # Fix related object access
|
||||
|
||||
|
||||
class CustomGalleryYearArchiveView(LoginRequiredMixin, GalleryYearArchiveView):
|
||||
"""
|
||||
Override to use event date
|
||||
"""
|
||||
date_field = 'extended__date_start'
|
||||
uses_datetime_field = False # Fix related object access
|
||||
|
||||
|
||||
class CustomGalleryDetailView(LoginRequiredMixin, DetailView):
|
||||
"""
|
||||
Custom gallery detail view to filter on photo owner
|
||||
"""
|
||||
queryset = Gallery.objects.on_site().is_public()
|
||||
queryset = Gallery.objects.filter(is_public=True)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
|
@ -104,10 +86,6 @@ class GalleryDownload(LoginRequiredMixin, DetailView):
|
|||
return response
|
||||
|
||||
|
||||
class CustomPhotoDetailView(LoginRequiredMixin, PhotoDetailView):
|
||||
pass
|
||||
|
||||
|
||||
class GalleryUpload(PermissionRequiredMixin, FormView):
|
||||
"""
|
||||
Form to upload new photos in a gallery
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
Django>=2.2.20
|
||||
django-photologue~=3.13
|
||||
django-taggit>=1.5.0
|
||||
django-crispy-forms~=1.7
|
||||
django-allauth>=0.44
|
||||
django-crispy-forms~=1.7
|
||||
django-taggit>=1.5.0
|
||||
Django>=2.2.20
|
||||
ExifRead>=2.1.2
|
||||
git+https://gitlab.crans.org/bde/allauth-note-kfet.git
|
||||
Pillow>=6.0.0
|
||||
4
tox.ini
4
tox.ini
|
|
@ -12,7 +12,7 @@ deps =
|
|||
-r{toxinidir}/requirements.txt
|
||||
coverage
|
||||
commands =
|
||||
coverage run --omit='photo21/wsgi.py' --source=photo21,photologue_custom ./manage.py test
|
||||
coverage run --omit='photo21/wsgi.py' --source=photo21,photologue,photologue_custom ./manage.py test
|
||||
coverage report -m
|
||||
|
||||
[testenv:linters]
|
||||
|
|
@ -26,7 +26,7 @@ deps =
|
|||
pep8-naming
|
||||
pyflakes
|
||||
commands =
|
||||
flake8 photo21 photologue_custom
|
||||
flake8 photo21 photologue photologue_custom
|
||||
|
||||
[flake8]
|
||||
ignore = W503, I100, I101
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue