Amélioration des pages utilisateurs pour les petits écrans (#578, #520)

- Refonte de l'organisation des pages utilisateurs (principalement du front)
  - Page des parrains/fillots
  - Page d'édition du profil
  - Page du profil
  - Page des outils
  - Page des préférences
  - Page des stats utilisateurs

- Refonte du CSS / organisation de la navbar principale (en haut de l'écran)
- Refonte du CSS de la navbar bleu clair (le menu)
- Refonte du CSS du SAS :
  - Page de photo
  - Page d'albums
This commit is contained in:
Julien Constant 2023-03-30 14:38:40 +02:00 committed by GitHub
parent 6c1fa6de0b
commit 28f397574f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 3415 additions and 1406 deletions

View File

@ -36,6 +36,7 @@ from django.core.exceptions import ValidationError
from django.utils import timezone from django.utils import timezone
from core import utils
from core.models import User, Preferences, RealGroup, Notification, SithFile from core.models import User, Preferences, RealGroup, Notification, SithFile
from club.models import Club from club.models import Club
@ -46,6 +47,7 @@ class Sith(models.Model):
alert_msg = models.TextField(_("alert message"), default="", blank=True) alert_msg = models.TextField(_("alert message"), default="", blank=True)
info_msg = models.TextField(_("info message"), default="", blank=True) info_msg = models.TextField(_("info message"), default="", blank=True)
weekmail_destinations = models.TextField(_("weekmail destinations"), default="") weekmail_destinations = models.TextField(_("weekmail destinations"), default="")
version = utils.get_git_revision_short_hash()
def is_owned_by(self, user): def is_owned_by(self, user):
return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) return user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)

View File

@ -82,7 +82,7 @@ class ComTest(TestCase):
self.assertContains( self.assertContains(
r, r,
"""<div id="alert_box"> """<div id="alert_box">
<div class="markdown"><h3>ALERTE!</h3> <div class="markdown"><h3>ALERTE!</h3>
<p><strong>Caaaataaaapuuuulte!!!!</strong></p>""", <p><strong>Caaaataaaapuuuulte!!!!</strong></p>""",
) )
@ -100,7 +100,7 @@ class ComTest(TestCase):
self.assertContains( self.assertContains(
r, r,
"""<div id="info_box"> """<div id="info_box">
<div class="markdown"><h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>""", <div class="markdown"><h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>""",
) )
def test_birthday_non_subscribed_user(self): def test_birthday_non_subscribed_user(self):

View File

@ -13,7 +13,7 @@ class Migration(migrations.Migration):
model_name="preferences", model_name="preferences",
name="receive_weekmail", name="receive_weekmail",
field=models.BooleanField( field=models.BooleanField(
default=False, verbose_name="do you want to receive the weekmail" default=False, verbose_name="receive the weekmail"
), ),
) )
] ]

View File

@ -783,9 +783,7 @@ class Preferences(models.Model):
user = models.OneToOneField( user = models.OneToOneField(
User, related_name="_preferences", on_delete=models.CASCADE User, related_name="_preferences", on_delete=models.CASCADE
) )
receive_weekmail = models.BooleanField( receive_weekmail = models.BooleanField(_("receive the Weekmail"), default=False)
_("do you want to receive the weekmail"), default=False
)
show_my_stats = models.BooleanField(_("show your stats to others"), default=False) show_my_stats = models.BooleanField(_("show your stats to others"), default=False)
notify_on_click = models.BooleanField( notify_on_click = models.BooleanField(
_("get a notification for every click"), default=False _("get a notification for every click"), default=False

View File

@ -0,0 +1,408 @@
.header {
box-sizing: border-box;
background-color: #354a5f;
box-shadow: 3px 3px 3px 0 #dfdfdf;
border-radius: 0;
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 10px;
gap: 10px;
@media (max-width: 700px) {
height: auto;
}
@media (max-width: 580px) {
justify-content: space-between;
}
&-logo {
display: flex;
flex-direction: row;
gap: 10px;
&:hover > a {
color: #1a78b3;
}
@media (max-width: 607px) {
width: 100%;
justify-content: center;
}
&-picture {
height: 100%;
width: 65px;
display: flex;
background-position: center center;
background-size: contain;
background-repeat: no-repeat;
@media (max-width: 580px) {
height: auto;
}
}
&-text {
color: white;
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
> span:first-child {
font-size: 1.43em;
}
> span:last-child {
font-size: .7em;
}
}
}
&-lang {
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 3px;
@media (max-width: 580px) {
flex-direction: row;
}
> form {
margin: 0;
box-sizing: border-box;
position: relative;
> input[type=submit] {
border-radius: 0;
margin: 0;
box-sizing: border-box;
background-color: #354a5f;
width: 45px;
height: 25px;
padding: 0;
color: white;
font-weight: normal;
line-height: 1.3em;
&:hover {
background-color: #283747;
}
}
}
}
&-disconnected {
box-sizing: border-box;
flex: 1;
display: flex;
justify-content: flex-end;
align-items: center;
@media (max-width: 607px) {
justify-content: center;
}
> .button {
box-sizing: border-box;
height: 35px;
background-color: transparent;
font-weight: normal;
padding: 5px 20px;
display: flex;
justify-content: center;
align-items: center;
text-transform: uppercase;
text-decoration: none;
color: white;
margin: 0;
font-size: .9em;
width: 120px;
&:hover {
background-color: #283747;
}
}
}
&-disconnected ~ &-lang {
@media (max-width: 662px) {
flex-direction: row;
width: 100%;
}
}
&-connected {
box-sizing: border-box;
flex: 1;
display: flex;
flex-direction: row;
@media (min-width: 400px) and (max-width: 1200px) {
flex-direction: column;
min-width: 100%;
justify-content: center;
align-items: center;
gap: 10px;
}
@media (max-width: 400px) {
flex-direction: column;
width: 100%;
gap: 10px;
padding: 0 10px;
}
> .right,
> .left {
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
@media (min-width: 400px) and (max-width: 1200px) {
width: 100%;
justify-content: space-between;
padding: 0 20px;
}
}
> .right {
flex: 1;
justify-content: flex-end;
> .user {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 15px;
@media (max-width: 1200px) {
width: 100%;
flex-direction: row-reverse;
}
> a > img {
width: 40px;
height: 40px;
border-radius: 50%;
}
> .options {
width: 100%;
display: flex;
justify-content: flex-end;
flex-direction: column;
gap: 5px;
@media (max-width: 1200px) {
justify-content: flex-start;
flex-direction: row;
gap: 15px;
}
> a {
text-align: right;
color: white;
&:hover {
color: #1a78b3;
}
&:last-child {
color: #eb2f06;
&:hover {
color: #cc2804;
}
}
}
}
}
> .notification {
height: 100%;
width: 55px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
> a {
color: white;
position: relative;
font-size: 25px;
&:hover {
color: #1a78b3;
}
> span {
color: white;
font-size: 14px;
display: flex;
justify-content: center;
align-items: center;
width: 10px;
height: 10px;
padding: 5px;
background-color: #eb2f06;
border-radius: 50%;
position: absolute;
top: -50%;
right: -50%;
}
}
> #header_notif {
box-sizing: border-box;
display: none;
position: absolute;
margin: 0;
background-color: whitesmoke;
top: calc(100% + 10px);
right: calc(50% - 30px);
width: 400px;
max-width: calc(100vw - 30px);
padding: 10px;
z-index: 100;
border-radius: 10px;
box-shadow: 3px 3px 3px 0 #767676;
> ul {
list-style-type: none;
margin: 0;
display: flex;
flex-direction: column;
gap: 10px;
max-height: 120px;
overflow-y: auto;
> li {
> a {
.datetime {
display: flex;
justify-content: flex-start;
gap: 10px;
font-style: italic;
font-size: .8em;
}
}
&.empty-notification {
text-align: center;
font-style: italic;
}
}
}
.options {
width: 100%;
display: flex;
justify-content: space-between;
margin-top: 10px;
> a {
color: black;
padding: 5px;
width: 50%;
display: flex;
justify-content: center;
text-align: center;
align-items: center;
border-radius: 5px;
&:hover {
background-color: rgba(0, 0, 0, .2);
}
}
}
}
}
}
> .left {
gap: 10px;
display: flex;
@media (max-width: 1200px) {
flex-direction: row-reverse;
}
@media (max-width: 550px) {
flex-direction: column-reverse;
}
> form {
margin: 0;
width: 200px;
@media (max-width: 550px) {
width: 100%;
}
> input[type=text] {
box-sizing: border-box;
max-width: 100%;
width: 100%;
height: 35px;
border-radius: 5px;
font-size: .9em;
margin: 0;
background-color: #283747;
padding: 0 10px;
color: white;
}
}
}
}
&-connected ~ &-lang {
@media (max-width: 1200px) {
flex-direction: row;
width: 100%;
}
}
}
.bars {
list-style-type: none;
min-width: 120px;
margin: 0;
padding: 0;
@media(max-width: 1200px) {
display: flex;
flex-direction: row;
gap: 20px;
}
> li > a {
display: flex;
color: white;
&:hover {
color: #1a78b3;
}
> span {
margin-left: 10px;
}
> i {
width: 16px;
display: flex;
justify-content: center;
align-items: center;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -1,5 +1,3 @@
console.log('Guy');
$( function() { $( function() {
buttons = $(".choose_file_button"); buttons = $(".choose_file_button");
popups = $(".choose_file_widget"); popups = $(".choose_file_widget");

View File

@ -0,0 +1,110 @@
nav.navbar {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: center;
background-color: hsl(203, 75%, 40%);
margin: 1em;
color: white;
border-radius: 0.6em;
@media (max-width: 500px) {
position: relative;
flex-direction: column;
align-items: flex-start;
gap: 0;
margin: .2em;
}
> .menu,
> .link {
box-sizing: border-box;
width: 130px;
height: 52px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
@media (max-width: 500px) {
width: 100%;
height: auto;
justify-content: flex-start;
&:first-child {
border-radius: .6em .6em 0 0;
}
&:last-child {
border-radius: 0 0 .6em .6em;
> .content {
box-shadow: 3px 3px 3px 0 #dfdfdf;
}
}
}
}
> .menu > .head,
> .link {
color: white;
padding: 10px 20px;
box-sizing: border-box;
@media (max-width: 500px) {
padding: 10px;
}
}
.link:hover,
.menu:hover {
background-color: rgba(0, 0, 0, .2);
}
> .menu:hover > .content,
> .menu > .head:hover + .content,
> .menu > .content:hover {
display: flex;
}
> .menu {
display: flex;
position: relative;
> .content {
z-index: 10;
display: none;
position: absolute;
top: 100%;
background-color: white;
margin: 0;
list-style-type: none;
width: 130px;
box-shadow: 3px 3px 3px 0 #dfdfdf;
flex-direction: column;
@media (max-width: 500px) {
position: absolute;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
box-shadow: inset 3px 3px 3px 0 #dfdfdf;
}
> li > a {
display: flex;
padding: 15px 20px;
@media (max-width: 500px) {
padding: 10px;
}
&:hover {
color: hsl(203, 75%, 40%);
background-color: rgba(0, 0, 0, .05);
}
}
}
}
}

View File

@ -76,6 +76,7 @@ button:not(:disabled),
input[type="button"]:not(:disabled), input[type="button"]:not(:disabled),
input[type="submit"]:not(:disabled), input[type="submit"]:not(:disabled),
input[type="reset"]:not(:disabled), input[type="reset"]:not(:disabled),
input[type="checkbox"]:not(:disabled),
input[type="file"]:not(:disabled) { input[type="file"]:not(:disabled) {
cursor: pointer; cursor: pointer;
} }
@ -99,6 +100,7 @@ textarea {
padding: 7px; padding: 7px;
font-size: 1.2em; font-size: 1.2em;
border-radius: 5px; border-radius: 5px;
font-family: sans-serif;
} }
select { select {
border: none; border: none;
@ -181,166 +183,6 @@ a {
/*--------------------------------HEADER-------------------------------*/ /*--------------------------------HEADER-------------------------------*/
#header_language_chooser {
position: absolute;
top: 2em;
left: 0.5em;
width: 3%;
min-width: 2.2em;
text-align: center;
input {
display: block;
width: 100%;
padding: 4px;
margin: 0px;
}
form {
display: block;
margin: 0.2em 0em;
width: 100%;
}
}
header {
width: 90%;
margin: 0 auto;
display: flex;
box-shadow: $shadow-color 0 0 15px;
border-top: none;
background-color: $primary-neutral-dark-color;
border-radius: 0px 0px 10px 10px;
#header_logo {
background-color: $white-color;
padding: 0.2em;
border-radius: 0 0 0 9px;
a {
display: flex;
align-items: center;
margin: 0px;
width: 100%;
height: 100%;
img {
max-width: 70%;
max-height: 100%;
margin: auto;
display: block;
}
}
}
#header_connect_links {
margin: 0.6em 0.6em 0 auto;
padding: 0.2em;
color: $white-color;
form {
display: inline;
width: 100%;
label {
display: inline;
}
}
}
#header_bar {
display: flex;
flex: auto;
flex-wrap: wrap;
align-items: center;
width: 80%;
a {
text-decoration: none;
margin: 0 1em;
font-weight: bold;
color: $white-color;
&:hover {
color: $secondary-color;
text-decoration: underline;
}
}
#header_bars_infos {
flex: initial;
list-style-type: none;
margin: 0.2em 0.2em;
}
#header_search {
display: inline-block;
flex: auto;
margin: 0.8em 0;
input {
width: 14ch;
}
}
#header_user_links {
display: flex;
flex: initial;
flex-wrap: wrap;
text-align: right;
margin: 0;
div {
display: inline;
padding: 1.2em 0;
&:first-child {
flex: auto;
}
}
.white {
background: $white-color;
a {
color: $black-color;
}
}
#header_notif {
display: none;
position: absolute;
max-height: 20em;
width: 22em;
overflow: auto;
list-style-type: none;
box-shadow: grey 1px 1px 5px;
background: white;
text-align: left;
font-size: 80%;
margin: 1.5em 0 0em -14em;
.header_notif_date {
font-weight: bold;
}
.header_notif_time {
color: grey;
}
a {
margin: 0;
color: $black-color;
&:hover {
color: $primary-dark-color;
}
}
li {
padding: 0.2em;
&:hover {
background: hsl(180, 14%, 77%);
}
}
li:last-child {
text-align: center;
a {
color: $primary-dark-color;
&:hover {
color: $primary-light-color;
}
}
}
}
}
}
}
#popupheader { #popupheader {
width: 88%; width: 88%;
margin: 0 auto; margin: 0 auto;
@ -350,8 +192,13 @@ header {
#info_boxes { #info_boxes {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
width: 90%; margin: 1em;
margin: 1em auto;
@media (max-width: 500px) {
margin: 0;
width: 100%;
}
#alert_box, #alert_box,
#info_box { #info_box {
flex: 49%; flex: 49%;
@ -388,75 +235,6 @@ header {
width: 90%; width: 90%;
margin: 20px auto 0; margin: 20px auto 0;
/*---------------------------------NAV---------------------------------*/ /*---------------------------------NAV---------------------------------*/
nav {
display: flex;
flex-wrap: wrap;
background-color: $primary-dark-color;
color: $white-color;
border-radius: 6px 6px 0 0;
box-shadow: $shadow-color 0 0 15px;
align-items: center;
a {
flex: auto;
text-align: center;
padding: 1.5em;
color: $white-color;
font-style: normal;
font-weight: bolder;
text-decoration: none;
&:hover {
background: $secondary-neutral-color;
color: $white-color;
&:first-of-type {
border-radius: 6px 0 0 0;
}
&:last-of-type {
border-radius: 0 6px 0 0;
}
}
}
.dropdown {
flex: auto;
text-align: center;
position: relative;
}
.dropbtn {
all: unset;
padding: 20px;
font-weight: bolder;
}
.dropdown-content {
display: none;
position: absolute;
overflow: auto;
width: 100%;
background-color: #f9f9f9;
box-shadow: 3px 3px 3px 0 $shadow-color;
z-index: 1;
}
.dropdown-content a {
float: none;
color: black;
padding: 12px 16px;
display: block;
text-align: center;
&:hover {
border-radius: unset;
color: white;
background: $secondary-neutral-color;
}
}
.dropdown:hover .dropdown-content {
display: block;
}
}
.btn { .btn {
font-size: 15px; font-size: 15px;
@ -1120,32 +898,26 @@ h6 {
h1 { h1 {
font-size: 160%; font-size: 160%;
margin-left: 0;
} }
h2 { h2 {
font-size: 150%; font-size: 150%;
margin-left: 10px;
} }
h3 { h3 {
font-size: 140%; font-size: 140%;
margin-left: 20px;
} }
h4 { h4 {
font-size: 130%; font-size: 130%;
margin-left: 30px;
} }
h5 { h5 {
font-size: 120%; font-size: 120%;
margin-left: 40px;
} }
h6 { h6 {
font-size: 110%; font-size: 110%;
margin-left: 50px;
} }
p, p,
@ -1328,88 +1100,6 @@ u,
/*-----------------------------USER PROFILE----------------------------*/ /*-----------------------------USER PROFILE----------------------------*/
#user_profile_page {
#user_profile {
display: flex;
justify-content: center;
margin-top: 2em;
margin-bottom: 4em;
#user_profile_infos {
flex-basis: 30%;
border-right: solid 1px grey;
div {
margin: 0.5em;
}
#user_profile_infos_items {
margin-top: 3em;
}
.user_profile_infos_item,
.user_profile_infos_item_value {
vertical-align: top;
display: inline-block;
width: 49%;
}
.user_profile_infos_item {
color: grey;
}
#user_profile_infos_promo {
display: flex;
align-items: center;
img {
width: 5em;
margin: 0.5em;
}
}
#user_profile_infos_quote {
text-align: right;
color: grey;
font-style: italic;
&:after,
&:before {
content: "\201C";
vertical-align: middle;
}
}
}
#user_profile_pictures {
height: 20em;
flex-basis: 30%;
display: flex;
justify-content: flex-end;
#user_profile_pictures_bigone {
flex-grow: 9;
flex-basis: 20em;
display: flex;
justify-content: center;
align-items: center;
img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
}
#user_profile_pictures_thumbnails {
flex-grow: 1;
flex-basis: 50px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
img {
margin: 0.1em;
width: 50px;
}
}
}
@media screen and (max-width: $small-devices) {
#user_profile_infos,
#user_profile_pictures {
flex-basis: 50%;
}
}
}
}
.user_mini_profile { .user_mini_profile {
height: 100%; height: 100%;
width: 100%; width: 100%;
@ -1691,47 +1381,6 @@ textarea {
} }
} }
/*------------------------------SAS------------------------------------*/
.album {
display: inline-block;
border: solid 1px $black-color;
text-align: center;
padding: 5px;
width: 200px;
height: 140px;
background: hsl(0, 0%, 93%);
box-shadow: black 2px 2px 10px;
margin: 10px;
vertical-align: top;
img {
max-height: 100px;
}
}
.picture {
display: inline-block;
border: solid 1px $black-color;
width: 150px;
height: 100px;
margin: 5px;
background: #eeeeee;
box-shadow: grey 2px 2px 5px;
padding: 2px;
vertical-align: middle;
img {
max-width: 100%;
max-height: 100px;
display: block;
margin: auto;
}
}
.not_moderated {
border: solid 1px red;
box-shadow: red 2px 2px 10px;
}
/*--------------------------------FOOTER-------------------------------*/ /*--------------------------------FOOTER-------------------------------*/
footer { footer {
@ -1747,6 +1396,7 @@ footer {
border-radius: 5px; border-radius: 5px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center;
background-color: $primary-neutral-dark-color; background-color: $primary-neutral-dark-color;
box-shadow: $shadow-color 0 0 15px; box-shadow: $shadow-color 0 0 15px;
a { a {
@ -1759,6 +1409,11 @@ footer {
} }
} }
} }
> .version {
margin-top: 3px;
color: rgba(0, 0, 0, .3)
}
} }
/*---------------------------------FORMS-------------------------------*/ /*---------------------------------FORMS-------------------------------*/

View File

@ -0,0 +1,24 @@
.activity-description {
display: flex;
flex-direction: column;
gap: 5px;
width: 100%;
margin-top: 10px;
> div {
display: flex;
flex-direction: row;
gap: 10px;
> span {
text-align: left;
}
> i {
width: 16px;
display: flex;
justify-content: center;
align-items: center;
}
}
}

249
core/static/sas/album.scss Normal file
View File

@ -0,0 +1,249 @@
main {
box-sizing: border-box;
padding: 10px;
}
.navbar {
margin-top: 10px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
justify-content: space-between;
}
.toolbar {
display: flex;
align-items: flex-end;
flex-wrap: wrap;
gap: 5px;
> a,
> input {
padding: 0.4em;
margin: 0.1em;
font-size: 1.2em;
line-height: 1.2em;
color: black;
background-color: #f2f2f2;
border-radius: 5px;
font-weight: bold;
&:hover {
background-color: #d4d4d4;
}
&:disabled {
background-color: #f2f2f2;
color: #d4d4d4;
}
}
}
.add-files {
display: flex;
flex-direction: column;
> .inputs {
align-items: flex-end;
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
> p {
box-sizing: border-box;
max-width: 300px;
width: 100%;
@media (max-width: 500px) {
max-width: 100%;
}
> input {
box-sizing: border-box;
max-width: 100%;
width: 100%;
height: 40px;
line-height: normal;
font-size: 16px;
}
}
> div > input,
> input {
box-sizing: border-box;
height: 40px;
width: 100%;
max-width: 300px;
@media (max-width: 500px) {
max-width: 100%;
}
}
> div {
width: 100%;
max-width: 300px;
}
> input[type=submit]:hover {
background-color: #287fb8;
color: white;
}
}
}
.clipboard {
margin-top: 10px;
padding: 10px;
background-color: rgba(0,0,0,.1);
border-radius: 10px;
}
.paginator {
display: flex;
justify-content: center;
gap: 10px;
width: -moz-fit-content;
width: fit-content;
background-color: rgba(0,0,0,.1);
border-radius: 10px;
padding: 10px;
margin: 10px 0 10px auto;
}
.photos,
.albums {
box-sizing: border-box;
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 5px;
> div {
background: rgba(0, 0, 0, .5);
cursor: not-allowed;
}
> div,
> a {
box-sizing: border-box;
position: relative;
height: 128px;
@media (max-width: 500px) {
width: calc(50% - 5px);
height: 108px;
}
@media (max-width: 300px) {
width: 100%;
}
&:hover {
background: rgba(0, 0, 0, .5);
}
> input[type=checkbox] {
position: absolute;
top: 0;
right: 0;
height: 15px;
width: 15px;
margin: 5px;
cursor: pointer;
}
> .photo,
> .album {
box-sizing: border-box;
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
width: calc(16 / 9 * 128px);
height: 128px;
margin: 0;
padding: 0;
box-shadow: none;
border: 1px solid rgba(0, 0, 0, .3);
@media (max-width: 500px) {
width: 100%;
height: 100%;
}
&:hover > .text {
background-color: rgba(0, 0, 0, .5);
}
&:hover > .overlay {
-webkit-backdrop-filter: blur(2px);
backdrop-filter: blur(2px);
~ .text {
background-color: transparent;
}
}
> .text {
position: absolute;
box-sizing: border-box;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: flex-start;
padding: 10px;
color: white;
}
> .overlay {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
&::before {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
content: '⚠️';
color: white;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, .5);
-webkit-backdrop-filter: blur(5px);
backdrop-filter: blur(5px);
}
}
}
> .album > div {
background: rgba(0, 0, 0, .5);
background: linear-gradient(0deg, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, 0) 100%);
text-align: left;
word-break: break-word;
}
> .photo > .text {
align-items: center;
padding-bottom: 30px;
}
}
}

View File

@ -0,0 +1,309 @@
#content {
padding: 10px !important;
}
.title {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.container {
display: flex;
flex-direction: row;
gap: 10px;
@media (max-width: 1000px) {
flex-direction: column;
}
}
.main {
display: flex;
flex-direction: column;
width: calc(75% - 5px);
gap: 10px;
@media (max-width: 1000px) {
width: 100%;
}
> .photo {
box-sizing: border-box;
height: 500px;
display: flex;
justify-content: center;
background-color: #333333;
padding: 5px;
@media (max-width: 1000px) {
width: 100%;
height: auto;
}
> img {
height: 100%;
max-width: 100%;
object-fit: contain;
}
}
}
.subsection {
width: calc(25% - 5px);
@media (max-width: 1000px) {
width: 100%;
}
> .navigation {
display: flex;
flex-direction: row;
gap: 10px;
@media (max-width: 1000px) {
width: 100%;
}
> #prev,
> #next {
width: calc(50% - 5px);
aspect-ratio: 16/9;
background: #aaa;
> a {
display: flex;
position: relative;
width: 100%;
height: 100%;
> div {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 30px;
color: white;
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
&::before {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, .3);
}
}
}
}
> #prev > a > div::before {
content: '';
}
> #next > a > div::before {
content: '';
}
}
> .tags {
@media (min-width: 1001px) {
margin-right: 5px;
}
> ul {
list-style-type: none;
margin: 0;
display: flex;
flex-direction: column;
gap: 5px;
@media (max-width: 1000px) {
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
margin-right: 5px;
}
> li {
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
justify-content: space-between;
@media (max-width: 1000px) {
max-width: calc(50% - 5px);
}
> a {
display: flex;
flex-direction: row;
align-items: center;
gap: 10px;
&.user {
width: 100%;
background-color: #eee;
padding: 5px 10px 5px 5px;
border-radius: 5px;
color: black;
max-width: calc(100% - 40px);
min-height: 30px;
&:hover {
background-color: #aaa;
}
> span {
width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
&.delete {
margin-left: 10px;
}
> img {
width: 25px;
max-height: 25px;
object-fit: contain;
border-radius: 50%;
}
}
}
}
> form {
> p {
box-sizing: border-box;
> input {
width: 100%;
max-width: 100%;
box-sizing: border-box;
}
}
> .results_on_deck > div {
position: relative;
display: flex;
align-items: center;
word-break: break-word;
> span {
position: absolute;
top: 0;
right: 0;
}
}
> input {
width: 100%;
max-width: 100%;
box-sizing: border-box;
}
}
}
}
.general {
display: flex;
flex-direction: row;
gap: 20px;
@media (max-width: 1000px) {
flex-direction: column;
}
> .infos {
display: flex;
flex-direction: column;
> div > div {
display: flex;
flex-direction: row;
justify-content: space-between;
> *:first-child {
min-width: 150px;
@media (max-width: 1000px) {
min-width: auto;
}
}
}
}
> .tools {
display: flex;
flex-direction: column;
width: 100%;
> div {
display: flex;
flex-direction: row;
justify-content: space-between;
> div {
> a.button {
box-sizing: border-box;
background-color: #f2f2f2;
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
color: black;
border-radius: 5px;
width: 40px;
height: 40px;
&:hover {
background-color: #aaa;
}
}
> a.text.danger {
color: red;
&:hover {
color: darkred;
}
}
&.buttons {
display: flex;
gap: 5px;
}
}
}
}
}
.moderation {
box-sizing: border-box;
width: 100%;
border: 2px solid coral;
border-radius: 2px;
padding: 10px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
> div:last-child {
display: flex;
gap: 20px;
}
}

108
core/static/user/login.scss Normal file
View File

@ -0,0 +1,108 @@
html,
body {
box-sizing: border-box;
height: 100%;
}
body {
display: flex;
flex-direction: column;
}
#page {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
#content {
display: flex;
flex-direction: column;
padding: 10px;
box-shadow: none;
background-color: white;
margin: 0;
> .title {
text-align: center;
margin: 0;
}
> div,
> form {
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
width: 100%;
max-width: 500px;
margin-top: 20px;
> p,
> div {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
margin: 0;
> label {
width: 100%;
@media (min-width: 500px) {
width: 300px;
}
}
}
> input,
> p > input,
> div > input {
box-sizing: border-box;
width: 100%;
max-width: 500px;
@media (min-width: 500px) {
max-width: 300px;
}
}
> .errorlist {
color: red;
text-align: center;
margin: 10px 0 0 0;
list-style-type: none;
}
> .required > .helptext {
text-align: center;
font-style: italic;
}
> .required:last-of-type {
box-sizing: border-box;
max-width: 300px;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
> label {
width: 100%;
}
> img {
width: 70px;
object-fit: contain;
}
> input {
width: 200px;
}
}
}
}
}

View File

@ -0,0 +1,200 @@
main {
box-sizing: border-box;
display: flex;
margin-bottom: 4em;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px;
width: 100%;
> .user_profile > .user_profile_infos {
@media (max-width: 960px) {
border-right-color: transparent;
}
}
}
.user-name {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
max-width: 1080px;
margin: 0 auto;
}
.infos-and-picture {
display: flex;
flex-direction: row;
justify-content: center;
width: 100%;
max-width: 1080px;
margin: 0 auto;
@media (max-width: 960px) {
flex-direction: column-reverse;
gap: 20px;
}
> .user_profile_infos {
width: 50%;
border-right: solid 1px grey;
@media (max-width: 960px) {
width: 100%;
}
@media (min-width: 960px) {
padding-right: 20px;
}
> .user_profile_infos_promo {
display: flex;
flex-direction: row;
gap: 10px;
align-items: center;
justify-content: center;
width: 100%;
> img {
width: 5em;
margin: 0.5em;
}
}
> .user_profile_infos_items {
margin-top: 30px;
display: flex;
flex-direction: column;
gap: 5px;
> div {
box-sizing: border-box;
display: flex;
> .user_profile_infos_item,
> .user_profile_infos_item_value {
vertical-align: top;
display: block;
width: 50%;
}
> .user_profile_infos_item {
color: gray;
}
}
}
> #user_profile_infos_quote {
text-align: right;
color: grey;
font-style: italic;
@media (max-width: 960px) {
text-align: center;
}
&:after,
&:before {
vertical-align: middle;
}
&:before {
content: "\201C";
}
&:after {
content: "\201D";
}
}
}
> .user_profile_pictures {
height: 20em;
width: 50%;
display: flex;
flex-direction: row;
justify-content: flex-end;
@media (max-width: 960px) {
width: 100%;
height: 100%;
flex-direction: column;
}
@media (min-width: 960px) {
padding-left: 20px;
}
> .user_profile_pictures_bigone {
flex-grow: 9;
flex-basis: 20em;
display: flex;
justify-content: center;
align-items: center;
> img {
max-height: 100%;
max-width: 100%;
object-fit: contain;
@media (max-width: 960px) {
max-width: 300px;
width: 100%;
object-fit: contain;
}
}
}
> .user_profile_pictures_thumbnails {
padding: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 20px;
flex-grow: 1;
@media (max-width: 960px) {
flex-direction: row;
height: 50%;
}
> img {
max-height: calc(100% / 3);
width: 100%;
object-fit: contain;
@media (max-width: 960px) {
max-height: 100%;
max-width: calc(100% / 3) !important;
height: auto;
}
}
}
}
}
.form-gifts {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: 10px;
@media (max-width: 960px) {
flex-direction: column;
}
>select,
>input {
min-width: 300px;
max-width: 100%;
height: 40px;
@media (max-width: 960px) {
width: 100%;
}
}
}

View File

@ -0,0 +1,193 @@
@media (max-width: 750px) {
.title {
text-align: center;
}
}
.field-error {
height: auto !important;
> ul {
list-style-type: none;
margin: 0;
color: indianred;
> li {
text-align: left !important;
line-height: normal;
margin-top: 5px;
}
}
}
.profile {
&-visible {
display: flex;
justify-content: center;
align-items: center;
gap: 5px;
padding-top: 10px;
}
&-pictures {
box-sizing: border-box;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
gap: 40px;
align-items: stretch;
@media (max-width: 750px) {
flex-direction: column;
gap: 10px
}
}
&-picture {
box-sizing: border-box;
display: flex;
justify-content: space-between;
flex-direction: column;
align-items: center;
flex-wrap: wrap;
gap: 20px;
width: 100%;
height: 100%;
max-width: 300px;
@media (max-width: 750px) {
max-width: 100%;
padding: 10px 10px 0;
}
&-display {
display: flex;
flex-direction: column;
justify-content: center;
height: 300px;
gap: 10px;
@media (max-width: 750px) {
height: auto;
}
>img {
width: 100% !important;
object-fit: contain;
height: auto;
}
>p {
text-align: left !important;
width: 100% !important;
}
}
&-edit {
display: flex;
flex-direction: column-reverse;
align-items: center;
justify-content: center;
width: 100%;
> a {
margin-bottom: 15px;
}
> input {
font-size: .8em;
font-weight: normal;
cursor: pointer;
}
> p {
margin-bottom: 0;
text-align: left !important;
min-height: 50px;
}
}
}
&-fields {
padding: 10px 10px 0;
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
}
&-field {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
width: 100%;
max-width: 330px;
min-width: 300px;
@media (max-width: 750px) {
gap: 4px;
max-width: 100%;
}
>* {
width: 100%;
max-width: 300px;
@media (max-width: 750px) {
max-width: 100%;
}
}
&-label {
text-align: left !important;
}
&-content {
>* {
box-sizing: border-box;
text-align: left !important;
line-height: 40px;
max-width: 100%;
width: 100%;
height: 40px;
margin: 0;
>* {
text-align: left !important;
}
}
>textarea {
height: 120px;
min-height: 40px;
min-width: 300px;
max-width: 300px;
line-height: initial;
@media (max-width: 750px) {
max-width: 100%;
}
}
>input[type="file"] {
font-size: small;
line-height: 30px;
}
>input[type="checkbox"] {
width: 20px;
height: 20px;
margin: 0;
float: left;
}
}
}
}

View File

@ -0,0 +1,113 @@
.container {
display: flex;
flex-direction: column;
gap: 10px;
padding: 10px;
box-sizing: border-box;
> form {
margin: 0;
}
}
.users {
display: flex;
flex-direction: row;
flex-wrap: wrap;
list-style-type: none;
margin: 0;
gap: 10px
}
.users-card {
display: flex;
flex-direction: column;
gap: 10px;
width: 150px;
padding: 10px;
background-color: rgba(0, 0, 0, .05);
border-radius: 10px;
@media (max-width: 375px) {
width: 100%;
}
// Django moment
> div.mini_profile_link {
position: relative;
> a {
&.mini_profile_link {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 10px;
@media (max-width: 375px) {
flex-direction: row;
justify-content: flex-start;
align-items: flex-start;
max-height: 65px;
}
> span {
height: 150px;
width: 100%;
@media (max-width: 375px) {
height: 80px;
width: 80px;
}
> img {
width: 100%;
max-width: 100%;
max-height: 100%;
height: auto;
object-fit: contain;
@media (max-width: 375px) {
max-width: 100%;
max-height: 80px;
}
}
}
> em {
box-sizing: border-box;
padding: 0 5px;
text-align: center;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
@media (max-width: 375px) {
margin-top: 10px;
text-align: left;
max-width: none;
width: 100%;
}
}
}
&:last-of-type {
margin-top: 10px;
display: block;
text-align: center;
color: orangered;
@media (max-width: 375px) {
position: absolute;
bottom: 0%;
right: 0;
}
}
}
}
// Django moment
> a.mini_profile_link {
display: none;
}
}

View File

@ -0,0 +1,12 @@
#id_groups {
margin: 0;
>li {
list-style-type: none;
padding-left: 20px;
>label {
cursor: pointer;
}
}
}

View File

@ -0,0 +1,58 @@
.form {
display: flex;
flex-direction: column;
margin: 10px 0;
gap: 5px;
&-general {
> p {
display: flex;
flex-direction: row-reverse;
justify-content: left;
align-items: center;
gap: 5px;
margin: 0;
> label {
cursor: pointer;
margin: 0;
}
}
}
&-cards,
&-trombi {
>p {
display: flex;
flex-direction: column;
align-items: flex-start;
text-align: justify;
gap: 5px;
margin: 0;
>input,
>select {
min-width: 300px;
}
}
}
&-submit-btn {
margin-top: 10px !important;
max-width: 100px;
}
}
.justify {
text-align: justify;
}
.main {
padding: 10px;
}
.no-cards,
.student-cards {
margin-top: 10px;
display: block;
}

View File

@ -0,0 +1,48 @@
.container {
padding: 10px;
display: flex;
flex-direction: column;
gap: 10px;
}
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
align-items: center;
margin-bottom: 10px;
gap: 30px;
@media (max-width: 535px) {
gap: 20px;
>div,
>div>.flexed {
width: 100%;
align-items: stretch;
}
}
}
.flexed {
display: flex;
flex-direction: column;
gap: 2px;
align-items: self-start;
>div {
display: flex;
justify-content: space-between;
>b,
>span {
width: 120px;
&:last-child {
text-align: right;
}
}
}
}

View File

@ -0,0 +1,41 @@
main {
box-sizing: border-box;
padding: 10px;
}
.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
> div {
border-radius: 10px;
background-color: rgba(0, 0, 0, .05);
width: 210px;
>h4 {
text-align: center;
}
>ul {
list-style-type: none;
margin: 20px 10px;
display: flex;
flex-direction: column;
gap: 10px;
}
}
@media (max-width: 550px) {
>div {
width: 100%;
background-color: transparent;
>h4 {
text-align: left;
}
}
}
}

View File

@ -2,27 +2,32 @@
<html lang="fr"> <html lang="fr">
<head> <head>
{% block head %} {% block head %}
<title>{% block title %}{% trans %}Welcome!{% endtrans %}{% endblock %} - Association des Étudiants UTBM</title> <title>{% block title %}{% trans %}Welcome!{% endtrans %}{% endblock %} - Association des Étudiants UTBM</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="{{ static('core/img/favicon.ico') }}"> <link rel="shortcut icon" href="{{ static('core/img/favicon.ico') }}">
<link rel="stylesheet" href="{{ static('core/base.css') }}"> <link rel="stylesheet" href="{{ static('core/base.css') }}">
<link rel="stylesheet" href="{{ static('core/jquery.datetimepicker.min.css') }}"> <link rel="stylesheet" href="{{ static('core/jquery.datetimepicker.min.css') }}">
<link rel="stylesheet" href="{{ static('ajax_select/css/ajax_select.css') }}"> <link rel="stylesheet" href="{{ static('ajax_select/css/ajax_select.css') }}">
<link rel="stylesheet" href="{{ scss('core/style.scss') }}"> <link rel="stylesheet" href="{{ scss('core/style.scss') }}">
{% block jquery_css %} <link rel="stylesheet" href="{{ scss('core/header.scss') }}">
{# Thile file is quite heavy (around 250kb), so declaring it in a block allows easy removal #} <link rel="stylesheet" href="{{ scss('core/navbar.scss') }}">
<link rel="stylesheet" href="{{ static('core/js/ui/jquery-ui.min.css') }}">
{% endblock %}
<link rel="preload" as="style" href="{{ static('core/font-awesome/css/font-awesome.min.css') }}" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="{{ static('core/font-awesome/css/font-awesome.min.css') }}"></noscript>
<script defer href="{{ static('core/font-awesome/js/fontawesone.min.js') }}"></script>
<!-- Jquery declared here to be accessible in every django widgets --> {% block jquery_css %}
<script src="{{ static('core/js/jquery-3.6.2.min.js') }}"></script> {# Thile file is quite heavy (around 250kb), so declaring it in a block allows easy removal #}
<!-- Put here to always have acces to those functions on django widgets --> <link rel="stylesheet" href="{{ static('core/js/ui/jquery-ui.min.css') }}">
<script src="{{ static('core/js/script.js') }}"></script> {% endblock %}
{% block additional_css %}{% endblock %}
{% block additional_js %}{% endblock %} <link rel="preload" as="style" href="{{ static('core/font-awesome/css/font-awesome.min.css') }}" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="{{ static('core/font-awesome/css/font-awesome.min.css') }}"></noscript>
<script defer href="{{ static('core/font-awesome/js/fontawesone.min.js') }}"></script>
<!-- Jquery declared here to be accessible in every django widgets -->
<script src="{{ static('core/js/jquery-3.6.2.min.js') }}"></script>
<!-- Put here to always have acces to those functions on django widgets -->
<script src="{{ static('core/js/script.js') }}"></script>
{% block additional_css %}{% endblock %}
{% block additional_js %}{% endblock %}
{% endblock %} {% endblock %}
</head> </head>
@ -33,197 +38,210 @@
{% csrf_token %} {% csrf_token %}
<!-- BEGIN HEADER --> <!-- BEGIN HEADER -->
{% block header %} {% block header %}
{% if not popup %} {% if not popup %}
<header> <header class="header">
<div id="header_language_chooser"> <div class="header-logo">
{% for language in LANGUAGES %} <a class="header-logo-picture" href="{{ url('core:index') }}" style="background-image: url('{{ static('core/img/logo_no_text.png') }}')">
<form action="{{ url('set_language') }}" method="post">{% csrf_token %} &nbsp;
<input name="next" value="{{ request.path }}" type="hidden" /> </a>
<input name="language" value="{{ language[0] }}" type="hidden" /> <a class="header-logo-text" href="{{ url('core:index') }}">
<input type="submit" value="{{ language[0]|upper }}" /> <span>Association des Étudiants</span>
</form> <span>de l'Université de Technologie de Belfort-Montbéliard</span>
{% endfor %} </a>
</div> </div>
<div id="header_logo"> {% if not user.is_authenticated %}
<a href="{{ url('core:index') }}"> <div class="header-disconnected">
<img src="{{ static('core/img/logo.png') }}" alt="AE logo"> <a class="button" href="{{ url('core:login') }}">{% trans %}Login{% endtrans %}</a>
</a> <a class="button" href="{{ url('core:register') }}">{% trans %}Register{% endtrans %}</a>
</div> </div>
{% if not user.is_authenticated %} {% else %}
<div id="header_connect_links"> <div class="header-connected">
<form method="post" action="{{ url('core:login') }}"> <div class="left">
{% csrf_token %} <form class="search" action="{{ url('core:search') }}" method="GET" id="header_search">
<label for="id_username">{% trans %}Username{% endtrans %}</label> <input class="header-input" type="text" placeholder="{% trans %}Search{% endtrans %}" name="query" id="search" />
<input id="id_username" maxlength="254" name="username" type="text"> <input type="submit" value="{% trans %}Search{% endtrans %}" style="display: none;" />
<label for="id_password">{% trans %}Password{% endtrans %}</label> </form>
<input type="password" name="password" id="id_password"> <ul class="bars">
<input type="submit" value="{% trans %}Login{% endtrans %}"> {% cache 100 "counters_activity" %}
</form> {% for bar in Counter.objects.annotate_has_barman(user).filter(type="BAR") %}
<a href="{{ url('core:register') }}"><button type="button">{% trans %}Register{% endtrans %}</button></a> <li>
</div> {# If the user is a barman, we redirect him directly to the barman page
else we redirect him to the activity page #}
{% if bar.has_annotated_barman %}
<a href="{{ url('counter:details', counter_id=bar.id) }}">
{% else %}
<a href="{{ url('counter:activity', counter_id=bar.id) }}">
{% endif %}
{% if bar.is_inactive() %}
<i class="fa fa-question" style="color: #f39c12"></i>
{% elif bar.is_open(): %}
<i class="fa fa-check" style="color: #2ecc71"></i>
{% else %}
<i class="fa fa-times" style="color: #eb2f06"></i>
{% endif %}
<span>{{ bar }}</span>
</a>
</li>
{% endfor %}
{% endcache %}
</ul>
</div>
<div class="right">
<div class="user">
<div class="options">
<a href="{{ url('core:user_tools') }}">{% trans %}Tools{% endtrans %}</a>
<a href="{{ url('core:logout') }}">{% trans %}Logout{% endtrans %}</a>
</div>
<a href="{{ url('core:user_profile', user_id=user.id) }}">
{% if user.profile_pict %}
<img src="{{ user.profile_pict.get_download_url() }}" alt="{% trans %}Profile{% endtrans %}" title="{% trans %}Profile{% endtrans %}" />
{% else %}
<img src="{{ static('core/img/unknown.jpg') }}" alt="{% trans %}Profile{% endtrans %}" title="{% trans %}Profile{% endtrans %}" />
{% endif %}
</a>
</div>
<div class="notification">
<a href="#" onclick="display_notif()">
<i class="fa fa-bell-o"></i>
{% set notification_count = user.notifications.filter(viewed=False).count() %}
{% if notification_count > 0 %}
<span>
{% if notification_count < 100 %}
{{ notification_count }}
{% else %}
&nbsp;
{% endif %}
</span>
{% endif %}
</a>
<div id="header_notif">
<ul>
{% if user.notifications.filter(viewed=False).count() > 0 %}
{% for n in user.notifications.filter(viewed=False).order_by('-date') %}
<li>
<a href="{{ url("core:notification", notif_id=n.id) }}">
<div class="datetime">
<span class="header_notif_date">
{{ n.date|localtime|date(DATE_FORMAT) }}
</span>
<span class="header_notif_time">
{{ n.date|localtime|time(DATETIME_FORMAT) }}
</span>
</div>
<div class="reason">
{{ n }}
</div>
</a>
</li>
{% endfor %}
{% else %}
<li class="empty-notification">{% trans %}You do not have any unread notification{% endtrans %}</li>
{% endif %}
</ul>
<div class="options">
<a href="{{ url('core:notification_list') }}">
{% trans %}View more{% endtrans %}
</a>
<a href="{{ url('core:notification_list') }}?see_all">
{% trans %}Mark all as read{% endtrans %}
</a>
</div>
</div>
</div>
</div>
</div>
{% endif %}
<div class="header-lang">
{% for language in LANGUAGES %}
<form action="{{ url('set_language') }}" method="post">
{% csrf_token %}
<input name="next" value="{{ request.path }}" type="hidden" />
<input name="language" value="{{ language[0] }}" type="hidden" />
<input type="submit" value="{% if language[0] == 'en' %}🇬🇧{% else %}🇫🇷{% endif %}" />
</form>
{% endfor %}
</div>
</header>
{% block info_boxes %}
<div id="info_boxes">
{% set sith = get_sith() %}
{% if sith.alert_msg %}
<div id="alert_box">
{{ sith.alert_msg|markdown }}
</div>
{% endif %}
{% if sith.info_msg %}
<div id="info_box">
{{ sith.info_msg|markdown }}
</div>
{% endif %}
</div>
{% endblock %}
{% else %} {% else %}
<div id="header_bar"> <div id="popupheader">{{ user.get_display_name() }}</div>
<ul id="header_bars_infos">
{% cache 100 "counters_activity" %}
{% for bar in Counter.objects.annotate_has_barman(user).filter(type="BAR") %}
<li>
{# If the user is a barman, we redirect him directly to the barman page
else we redirect him to the activity page #}
{% if bar.has_annotated_barman %}
<a href="{{ url('counter:details', counter_id=bar.id) }}" style="padding: 0">
{% else %}
<a href="{{ url('counter:activity', counter_id=bar.id) }}" style="padding: 0">
{% endif %}
{% if bar.is_inactive(): %}
<i class="fa fa-question" style="color: #f39c12"></i>
{% elif bar.is_open(): %}
<i class="fa fa-check" style="color: #2ecc71"></i>
{% else %}
<i class="fa fa-times" style="color: #eb2f06"></i>
{% endif %}
{{ bar }}
</a>
</li>
{% endfor %}
</ul>
{% endcache %}
<form action="{{ url('core:search') }}" method="GET" id="header_search">
<input type="text" placeholder="{% trans %}Search{% endtrans %}" name="query" id="search" />
<input type="submit" value="{% trans %}Search{% endtrans %}" style="display: none;" />
</form>
<div id="header_user_links">
<div>
<a href="{{ url('core:user_profile', user_id=user.id) }}">{{ user.get_display_name() }}</a>
</div>
<div>
<a href="#" onclick="display_notif()" style="white-space: nowrap;"><i class="fa fa-bell-o"></i> ({{ user.notifications.filter(viewed=False).count() }})</a>
<ul id="header_notif">
{% for n in user.notifications.filter(viewed=False).order_by('-date') %}
<li>
<a href="{{ url("core:notification", notif_id=n.id) }}">
<span class="header_notif_date">
{{ n.date|localtime|date(DATE_FORMAT) }}
</span>
<span class="header_notif_time">
{{ n.date|localtime|time(DATETIME_FORMAT) }}
</span>
<br>
{{ n }}
</a>
</li>
{% endfor %}
<li>
<strong>
<a href="{{ url('core:notification_list') }}">
{% trans %}View more{% endtrans %}
</a>
<br />
<a href="{{ url('core:notification_list') }}?see_all">
{% trans %}Mark all as read{% endtrans %}
</a>
</strong>
</li>
</ul>
</div>
<div>
<a href="{{ url('core:user_tools') }}">{% trans %}Tools{% endtrans %}</a>
</div>
<div>
<a href="{{ url('core:logout') }}">{% trans %}Logout{% endtrans %}</a>
</div>
</div>
</div>
{% endif %} {% endif %}
</header>
<div id="info_boxes">
{% block info_boxes %}
{% set sith = get_sith() %}
{% if sith.alert_msg %}
<div id="alert_box">
{{ sith.alert_msg|markdown }}
</div>
{% endif %}
{% if sith.info_msg %}
<div id="info_box">
{{ sith.info_msg|markdown }}
</div>
{% endif %}
{% endblock %}
</div>
{% else %}{# if not popup #}
<div id="popupheader">{{ user.get_display_name() }}</div>
{% endif %}
{% endblock %} {% endblock %}
<!-- END HEADER --> <!-- END HEADER -->
{% block nav %}
{% if not popup %}
<nav class="navbar">
<a class="link" href="{{ url('core:index') }}">{% trans %}Main{% endtrans %}</a>
<div class="menu">
<span class="head">{% trans %}Associations & Clubs{% endtrans %}</span>
<ul class="content">
<li><a href="{{ url('core:page', page_name='ae') }}">{% trans %}AE{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='clubs') }}">{% trans %}AE's clubs{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='bdf') }}">{% trans %}BdF{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='bds') }}">{% trans %}BDS{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='cetu') }}">{% trans %}CETU{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='clubs/doceo') }}">{% trans %}Doceo{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='positions') }}">{% trans %}Positions{% endtrans %}</a></li>
</ul>
</div>
<div class="menu">
<span class="head">{% trans %}Events{% endtrans %}</span>
<ul class="content">
<li><a href="{{ url('election:list') }}">{% trans %}Elections{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='ga') }}">{% trans %}Big event{% endtrans %}</a></li>
</ul>
</div>
<a class="link" href="{{ url('forum:main') }}">{% trans %}Forum{% endtrans %}</a>
<a class="link" href="{{ url('sas:main') }}">{% trans %}Gallery{% endtrans %}</a>
<a class="link" href="{{ url('eboutic:main') }}">{% trans %}Eboutic{% endtrans %}</a>
<div class="menu">
<span class="head">{% trans %}Services{% endtrans %}</span>
<ul class="content">
<li><a href="{{ url('matmat:search_clear') }}">{% trans %}Matmatronch{% endtrans %}</a></li>
<li><a href="/launderette">{% trans %}Launderette{% endtrans %}</a></li>
<li><a href="{{ url('core:file_list') }}">{% trans %}Files{% endtrans %}</a></li>
<li><a href="{{ url('pedagogy:guide') }}">{% trans %}Pedagogy{% endtrans %}</a></li>
</ul>
</div>
<div class="menu">
<span class="head">{% trans %}My Benefits{% endtrans %}</span>
<ul class="content">
<li><a href="{{ url('core:page', page_name='partenaires')}}">{% trans %}Sponsors{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='avantages') }}">{% trans %}Subscriber benefits{% endtrans %}</a></li>
</ul>
</div>
<div class="menu">
<span class="head">{% trans %}Help{% endtrans %}</span>
<ul class="content">
<li><a href="{{ url('core:page', page_name='FAQ') }}">{% trans %}FAQ{% endtrans %}</a></li>
<li><a href="{{ url('core:page', 'contacts') }}">{% trans %}Contacts{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='Index') }}">{% trans %}Wiki{% endtrans %}</a></li>
</ul>
</div>
</nav>
{% endif %}
{% endblock %}
<div id="page"> <div id="page">
{% block nav %}
{% if not popup %}
<nav>
<a href="{{ url('core:index') }}">{% trans %}Main{% endtrans %}</a>
<div class="dropdown">
<button class="dropbtn">{% trans %}Associations & Clubs{% endtrans %}
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content">
<a href="{{ url('core:page', page_name='ae') }}">{% trans %}AE{% endtrans %}</a>
<a href="{{ url('core:page', page_name='clubs') }}">{% trans %}AE's clubs{% endtrans %}</a>
<a href="{{ url('core:page', page_name='bdf') }}">{% trans %}BdF{% endtrans %}</a>
<a href="{{ url('core:page', page_name='bds') }}">{% trans %}BDS{% endtrans %}</a>
<a href="{{ url('core:page', page_name='cetu') }}">{% trans %}CETU{% endtrans %}</a>
<a href="{{ url('core:page', page_name='clubs/doceo') }}">{% trans %}Doceo{% endtrans %}</a>
<a href="{{ url('core:page', page_name='positions') }}">{% trans %}Positions{% endtrans %}</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn">{% trans %}Events{% endtrans %}
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content">
<a href="{{ url('election:list') }}">{% trans %}Elections{% endtrans %}</a>
<a href="{{ url('core:page', page_name='ga') }}">{% trans %}Big event{% endtrans %}</a>
</div>
</div>
<a href="{{ url('forum:main') }}">{% trans %}Forum{% endtrans %}</a>
<a href="{{ url('sas:main') }}">{% trans %}Gallery{% endtrans %}</a>
<a href="{{ url('eboutic:main') }}">{% trans %}Eboutic{% endtrans %}</a>
<div class="dropdown">
<button class="dropbtn">{% trans %}Services{% endtrans %}
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content">
<a href="{{ url('matmat:search_clear') }}">{% trans %}Matmatronch{% endtrans %}</a>
<a href="/launderette">{% trans %}Launderette{% endtrans %}</a>
<a href="{{ url('core:file_list') }}">{% trans %}Files{% endtrans %}</a>
<a href="{{ url('pedagogy:guide') }}">{% trans %}Pedagogy{% endtrans %}</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn">{% trans %}My Benefits{% endtrans %}
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content">
<a href="{{ url('core:page', page_name='partenaires')}}">{% trans %}Sponsors{% endtrans %}</a>
<a href="{{ url('core:page', page_name='avantages') }}">{% trans %}Subscriber benefits{% endtrans %}</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn">{% trans %}Help{% endtrans %}
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content">
<a href="{{ url('core:page', page_name='FAQ') }}">{% trans %}FAQ{% endtrans %}</a>
<a href="{{ url('core:page', 'contacts') }}">{% trans %}Contacts{% endtrans %}</a>
<a href="{{ url('core:page', page_name="Index") }}">{% trans %}Wiki{% endtrans %}</a>
</div>
</div>
</nav>
{% endif %}
{% endblock %}
<ul id="quick_notif"> <ul id="quick_notif">
{% for n in quick_notifs %} {% for n in quick_notifs %}
@ -232,20 +250,15 @@
</ul> </ul>
<div id="content"> <div id="content">
{% if list_of_tabs %} {% if list_of_tabs %}
<div class="tool_bar"> <div class="tool_bar">
<div>{{ tabs_title }}</div> <div class="tools">
<div class="tools"> {% for t in list_of_tabs -%}
{% for t in list_of_tabs -%} <a href="{{ t.url }}" {%- if current_tab==t.slug %} class="selected_tab" {%- endif -%}>{{ t.name }}</a>
<a href="{{ t.url }}" {%- endfor %}
{%- if current_tab == t.slug %} </div>
class="selected_tab" </div>
{%- endif -%} {% endif %}
>{{ t.name }}</a>
{%- endfor %}
</div>
</div>
{% endif %}
{% if error %} {% if error %}
{{ error }} {{ error }}
@ -256,18 +269,24 @@
</div> </div>
{% if not popup %} {% if not popup %}
<footer> <footer>
{% block footer %} {% block footer %}
<div> <div>
<a href="{{ url('core:page', 'contacts') }}">{% trans %}Contacts{% endtrans %}</a> <a href="{{ url('core:page', 'contacts') }}">{% trans %}Contacts{% endtrans %}</a>
<a href="{{ url('core:page', 'legals') }}">{% trans %}Legal notices{% endtrans %}</a> <a href="{{ url('core:page', 'legals') }}">{% trans %}Legal notices{% endtrans %}</a>
<a href="{{ url('core:page', 'copyright_agent') }}">{% trans %}Intellectual property{% endtrans %}</a> <a href="{{ url('core:page', 'copyright_agent') }}">{% trans %}Intellectual property{% endtrans %}</a>
<a href="{{ url('core:page', 'docs') }}">{% trans %}Help & Documentation{% endtrans %}</a> <a href="{{ url('core:page', 'docs') }}">{% trans %}Help & Documentation{% endtrans %}</a>
<a href="{{ url('core:page', 'rd') }}">{% trans %}R&D{% endtrans %}</a> <a href="{{ url('core:page', 'rd') }}">{% trans %}R&D{% endtrans %}</a>
</div> </div>
{% trans %}Site made by good people{% endtrans %} <a href="https://discord.gg/XK9WfPsUFm" target="_link">
{% endblock %} {% trans %}Site created by the IT Department of the AE{% endtrans %}
</footer> </a>
{% endblock %}
<br>
<code class="version">
{% trans %}Sith version:{% endtrans %}&nbsp;{{ get_sith().version }}
</code>
</footer>
{% endif %} {% endif %}
<!-- <!--
{% block tests %} {% block tests %}

View File

@ -1,35 +1,61 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('user/login.scss') }}">
{%- endblock -%}
{% block title %} {% block title %}
{% trans %}Login{% endtrans %} {% trans %}Login{% endtrans %}
{% endblock %}
{% block info_boxes %}
{% endblock %}
{% block nav %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<h1 class="title">{% trans %}Login{% endtrans %}</h1>
{% if form.errors %} {% if next %}
<p>{% trans %}Your username and password didn't match. Please try again.{% endtrans %}</p> {% if user.is_authenticated %}
{% endif %} <p>{% trans %}Your account doesn't have access to this page. To proceed,
please login with an account that has access.{% endtrans %}</p>
{% if next %} {% else %}
{% if user.is_authenticated %} <p>{% trans %}Please login or create an account to see this page.{% endtrans %}</p>
<p>{% trans %}Your account doesn't have access to this page. To proceed, {% endif %}
please login with an account that has access.{% endtrans %}</p>
{% else %}
<p>{% trans %}Please login or create an account to see this page.{% endtrans %}</p>
{% endif %} {% endif %}
{% endif %}
<form method="post" action="{{ url('core:login') }}"> <form method="post" action="{{ url('core:login') }}">
{% csrf_token %} {% if form.errors %}
<p>{{ form.username.errors }}<label for="{{ form.username.name }}">{{ form.username.label }} <p class="alert alert-red">{% trans %}Your username and password didn't match. Please try again.{% endtrans %}</p>
</label><input id="id_username" maxlength="254" name="username" type="text" autofocus="autofocus" /></p> <br>
<p>{{ form.password.errors }}<label for="{{ form.password.name }}">{{ form.password.label }}</label>{{ form.password }}</p> {% endif %}
<input type="hidden" name="next" value="{{ next }}">
<p><input type="submit" value="{% trans %}login{% endtrans %}"></p>
</form>
{# Assumes you setup the password_reset view in your URLconf #} {% csrf_token %}
<p><a href="{{ url('core:password_reset') }}">{% trans %}Lost password?{% endtrans %}</a></p>
<p><a href="{{ url('core:register') }}">{% trans %}Create account{% endtrans %}</a></p>
<div>
<label for="{{ form.username.name }}">{{ form.username.label }}</label>
<input id="id_username" maxlength="254" name="username" type="text" autofocus="autofocus" />
{{ form.username.errors }}
</div>
<div>
<label for="{{ form.password.name }}">{{ form.password.label }}</label>
{{ form.password }}
{{ form.password.errors }}
</div>
<input type="hidden" name="next" value="{{ next }}">
<input type="submit" value="{% trans %}Login{% endtrans %}">
{# Assumes you setup the password_reset view in your URLconf #}
<p>
<a href="{{ url('core:password_reset') }}">{% trans %}Lost password?{% endtrans %}</a>
&nbsp;&nbsp;
<a href="{{ url('core:register') }}">{% trans %}Create account{% endtrans %}</a>
</p>
</form>
{% endblock %} {% endblock %}

View File

@ -1,20 +1,31 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %}{% trans %}Register a user{% endtrans %}{% endblock %} {%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('user/login.scss') }}">
{%- endblock -%}
{% block title %}{% trans %}Register{% endtrans %}{% endblock %}
{% block nav %}
{% endblock %}
{% block info_boxes %}
{% endblock %}
{% block content %} {% block content %}
<h1>{% trans %}Register a user{% endtrans %}</h1> <h1 class="title">{% trans %}Register{% endtrans %}</h1>
{% if user_registered %} {% if user_registered %}
{% trans user_name=user_registered.get_display_name() %}Welcome {{ user_name }}!{% endtrans %} {% trans user_name=user_registered.get_display_name() %}Welcome {{ user_name }}!{% endtrans %}<br>
{% trans %}You successfully registred and you will soon receive a confirmation mail.{% endtrans %} {% trans %}You successfully registred and you will soon receive a confirmation mail.{% endtrans %}<br>
{% trans username=user_registered.username %}Your username is {{ username }}.{% endtrans %}<br>
{% trans username=user_registered.username %}Your username is {{ username }}.{% endtrans %}
{% endif %} {% else %}
<form action="{{ url('core:register') }}" method="post">
<form action="{{ url('core:register') }}" method="post"> {% csrf_token %}
{% csrf_token %} {{ form }}
{{ form }} <input type="submit" value="{% trans %}Register{% endtrans %}" />
<p><input type="submit" value="{% trans %}Register{% endtrans %}" /></p> </form>
</form> {% endif %}
{% endblock %} {% endblock %}

View File

@ -1,6 +1,10 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% from "core/macros.jinja" import show_slots, show_tokens, user_subscription %} {% from "core/macros.jinja" import show_slots, show_tokens, user_subscription %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('user/user_detail.scss') }}">
{%- endblock -%}
{% block title %} {% block title %}
{% trans user_name=profile.get_display_name() %}{{ user_name }}'s profile{% endtrans %} {% trans user_name=profile.get_display_name() %}{{ user_name }}'s profile{% endtrans %}
{% endblock %} {% endblock %}
@ -10,144 +14,149 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="user_profile_page" x-data> <div class="user_profile_page" x-data>
<div id="user_profile"> <div class="user_profile">
<!-- Profile --> <!-- Profile -->
<div id="user_profile_infos"> <div class="user-name">
<h4>{{ profile.get_full_name() }}</h4> <h3>{{ profile.get_full_name() }}</h3>
{% if profile.nick_name %} {% if profile.nick_name %}
<div id="user_profile_infos_nick">&laquo; {{ profile.nick_name }} &raquo;</div> <div class="user_profile_infos_nick">&laquo; {{ profile.nick_name }} &raquo;</div>
{% endif %} {% endif %}
</div>
<div class="infos-and-picture">
<div class="user_profile_infos">
{% if profile.quote %} {% if profile.quote %}
<div id="user_profile_infos_quote"> <div class="user_profile_infos_quote">
{{ profile.quote }} {{ profile.quote }}
</div> </div>
{% endif %} {% endif %}
<div id="user_profile_infos_items"> <div class="user_profile_infos_items">
{% if profile.pronouns %} {% if profile.pronouns %}
<div> <div>
<span class="user_profile_infos_item">{% trans %}Pronouns: {% endtrans %}</span> <span class="user_profile_infos_item">{% trans %}Pronouns: {% endtrans %}</span>
<span class="user_profile_infos_item_value">{{ profile.pronouns }}</span> <span class="user_profile_infos_item_value">{{ profile.pronouns }}</span>
</div> </div>
{% endif %} {% endif %}
{% if profile.date_of_birth %} {% if profile.date_of_birth %}
<div> <div>
<span class="user_profile_infos_item">{% trans %}Born: {% endtrans %}</span> <span class="user_profile_infos_item">{% trans %}Born: {% endtrans %}</span>
<span class="user_profile_infos_item_value">{{ profile.date_of_birth|date("d/m/Y") }}</span> <span class="user_profile_infos_item_value">{{ profile.date_of_birth|date("d/m/Y") }}</span>
</div> </div>
{% endif %} {% endif %}
{% if profile.department != "NA" %} {% if profile.department != "NA" %}
<div> <div>
<span class="user_profile_infos_item">{% trans %}Department: {% endtrans %}</span> <span class="user_profile_infos_item">{% trans %}Department: {% endtrans %}</span>
<span class="user_profile_infos_item_value">{{ profile.department }}{{ profile.semester }}</span> <span class="user_profile_infos_item_value">{{ profile.department }}{{ profile.semester
}}</span>
</div> </div>
{% endif %} {% endif %}
{% if profile.dpt_option %} {% if profile.dpt_option %}
<div> <div>
<span class="user_profile_infos_item">{% trans %}Option: {% endtrans %}</span> <span class="user_profile_infos_item">{% trans %}Option: {% endtrans %}</span>
<span class="user_profile_infos_item_value">{{ profile.dpt_option }}</span> <span class="user_profile_infos_item_value">{{ profile.dpt_option }}</span>
</div> </div>
{% endif %} {% endif %}
{% if profile.phone %} {% if profile.phone %}
<div> <div>
<span class="user_profile_infos_item">{% trans %}Phone: {% endtrans %}</span> <span class="user_profile_infos_item">{% trans %}Phone: {% endtrans %}</span>
<span class="user_profile_infos_item_value">{{ profile.phone }}</span> <span class="user_profile_infos_item_value">{{ profile.phone }}</span>
</div> </div>
{% endif %} {% endif %}
{% if profile.address %} {% if profile.address %}
<div> <div>
<span class="user_profile_infos_item">{% trans %}Address: {% endtrans %}</span> <span class="user_profile_infos_item">{% trans %}Address: {% endtrans %}</span>
<span class="user_profile_infos_item_value">{{ profile.address }}</span> <span class="user_profile_infos_item_value">{{ profile.address }}</span>
</div> </div>
{% endif %} {% endif %}
{% if profile.parent_address %} {% if profile.parent_address %}
<div> <div>
<span class="user_profile_infos_item">{% trans %}Parents address: {% endtrans %}</span> <span class="user_profile_infos_item">{% trans %}Parents address: {% endtrans %}</span>
<span class="user_profile_infos_item_value">{{ profile.parent_address }}</span> <span class="user_profile_infos_item_value">{{ profile.parent_address }}</span>
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% if profile.promo %} {% if profile.promo %}
<div id="user_profile_infos_promo"> <div class="user_profile_infos_promo">
<img src="{{ static('core/img/promo_%02d.png' % profile.promo) }}" alt="Promo {{ profile.promo }}" /> {% trans %}Promo: {% endtrans %}{{ profile.promo }}
{% trans %}Promo: {% endtrans %}{{ profile.promo }} <img src="{{ static('core/img/promo_%02d.png' % profile.promo) }}"
alt="Promo {{ profile.promo }}" />
</div> </div>
{% endif %}
</div>
<!-- Pictures -->
<div id="user_profile_pictures">
<div id="user_profile_pictures_bigone">
{% if profile.profile_pict %}
<img src="{{ profile.profile_pict.get_download_url() }}" alt="{% trans %}Profile{% endtrans %}"
title="{% trans %}Profile{% endtrans %}" />
{% else %}
<img src="{{ static('core/img/unknown.jpg') }}" alt="{% trans %}Profile{% endtrans %}"
title="{% trans %}Profile{% endtrans %}" />
{% endif %} {% endif %}
</div> </div>
<div id="user_profile_pictures_thumbnails"> <!-- Pictures -->
{% if profile.profile_pict %} <div class="user_profile_pictures">
<div class="user_profile_pictures_bigone">
{% if profile.profile_pict %}
<img src="{{ profile.profile_pict.get_download_url() }}" alt="{% trans %}Profile{% endtrans %}" <img src="{{ profile.profile_pict.get_download_url() }}" alt="{% trans %}Profile{% endtrans %}"
title="{% trans %}Profile{% endtrans %}" /> title="{% trans %}Profile{% endtrans %}" />
{% else %} {% else %}
<img src="{{ static('core/img/unknown.jpg') }}" alt="{% trans %}Profile{% endtrans %}" <img src="{{ static('core/img/unknown.jpg') }}" alt="{% trans %}Profile{% endtrans %}"
title="{% trans %}Profile{% endtrans %}" /> title="{% trans %}Profile{% endtrans %}" />
{% endif %} {% endif %}
</div>
<div class="user_profile_pictures_thumbnails">
{% if profile.profile_pict %}
<img src="{{ profile.profile_pict.get_download_url() }}" alt="{% trans %}Profile{% endtrans %}"
title="{% trans %}Profile{% endtrans %}" />
{% else %}
<img src="{{ static('core/img/unknown.jpg') }}" alt="{% trans %}Profile{% endtrans %}"
title="{% trans %}Profile{% endtrans %}" />
{% endif %}
{% if profile.avatar_pict %} {% if profile.avatar_pict %}
<img src="{{ profile.avatar_pict.get_download_url() }}" alt="{% trans %}Avatar{% endtrans %}" <img src="{{ profile.avatar_pict.get_download_url() }}" alt="{% trans %}Avatar{% endtrans %}"
title="{% trans %}Avatar{% endtrans %}" /> title="{% trans %}Avatar{% endtrans %}" />
{% else %} {% else %}
<img src="{{ static('core/img/unknown.jpg') }}" alt="{% trans %}Avatar{% endtrans %}" <img src="{{ static('core/img/unknown.jpg') }}" alt="{% trans %}Avatar{% endtrans %}"
title="{% trans %}Avatar{% endtrans %}" /> title="{% trans %}Avatar{% endtrans %}" />
{% endif %} {% endif %}
{% if profile.scrub_pict %} {% if profile.scrub_pict %}
<img src="{{ profile.scrub_pict.get_download_url() }}" alt="{% trans %}Scrub{% endtrans %}" <img src="{{ profile.scrub_pict.get_download_url() }}" alt="{% trans %}Scrub{% endtrans %}"
title="{% trans %}Scrub{% endtrans %}" /> title="{% trans %}Scrub{% endtrans %}" />
{% else %} {% else %}
<img src="{{ static('core/img/unknown.jpg') }}" alt="{% trans %}Scrub{% endtrans %}" <img src="{{ static('core/img/unknown.jpg') }}" alt="{% trans %}Scrub{% endtrans %}"
title="{% trans %}Scrub{% endtrans %}" /> title="{% trans %}Scrub{% endtrans %}" />
{% endif %} {% endif %}
</div>
</div> </div>
</div> </div>
</div> </main>
{% if user.memberships.filter(end_date=None).exists() or user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or user ==
{% if user.memberships.filter(end_date=None).exists() or user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or user == profile or user.is_in_group(settings.SITH_BAR_MANAGER_BOARD_GROUP) %} profile or user.is_in_group(settings.SITH_BAR_MANAGER_BOARD_GROUP) %}
{# if the user is member of a club, he can view the subscription state #} {# if the user is member of a club, he can view the subscription state #}
<hr> <hr>
{% if profile.is_subscribed %} {% if profile.is_subscribed %}
{% if user == profile or user.is_root or user.is_board_member %} {% if user == profile or user.is_root or user.is_board_member %}
<div> <div>
{{ user_subscription(profile) }} {{ user_subscription(profile) }}
</div> </div>
{% endif %} {% endif %}
{% if user == profile or user.is_root or user.is_board_member or user.is_launderette_manager %} {% if user == profile or user.is_root or user.is_board_member or user.is_launderette_manager %}
<div> <div>
{# Shows tokens bought by the user #} {# Shows tokens bought by the user #}
{{ show_tokens(profile) }} {{ show_tokens(profile) }}
{# Shows slots took by the user #} {# Shows slots took by the user #}
{{ show_slots(profile) }} {{ show_slots(profile) }}
</div> </div>
{% endif %} {% endif %}
{% else %} {% else %}
<div> <div>
{% trans %}Not subscribed{% endtrans %} {% trans %}Not subscribed{% endtrans %}
{% if user.is_board_member %} {% if user.is_board_member %}
<a href="{{ url('subscription:subscription') }}?member={{ profile.id }}">{% trans %}New subscription{% endtrans %}</a> <a href="{{ url('subscription:subscription') }}?member={{ profile.id }}">{% trans %}New subscription{% endtrans
{% endif %} %}</a>
{% endif %} {% endif %}
</div> {% endif %}
</div>
{% endif %} {% endif %}
{% if profile.was_subscribed and (user == profile or user.can_read_subscription_history)%} {% if profile.was_subscribed and (user == profile or user.can_read_subscription_history)%}
<div class="collapse" :class="{'shadow': collapsed}" x-data="{collapsed: false}" x-cloak> <div class="collapse" :class="{'shadow': collapsed}" x-data="{collapsed: false}" x-cloak>
@ -183,9 +192,9 @@
{% endif %} {% endif %}
{% if user.is_root or user.is_board_member %} {% if user.is_root or user.is_board_member %}
<hr>
<div> <div>
<hr> <form class="form-gifts" action="{{ url('core:user_gift_create', user_id=profile.id) }}" method="post">
<form style="margin-left: 0px;" action="{{ url('core:user_gift_create', user_id=profile.id) }}" method="post">
{% csrf_token %} {% csrf_token %}
{{ gift_form.label }} {{ gift_form.label }}
{{ gift_form.user }} {{ gift_form.user }}
@ -212,11 +221,11 @@
</a> </a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
</div>
</div> </div>
</div>
{% else %} {% else %}
{% trans %}No gift given yet{% endtrans %} <em>{% trans %}No gift given yet{% endtrans %}</em>
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}
@ -228,33 +237,33 @@
{% block script %} {% block script %}
{{ super() }} {{ super() }}
<script> <script>
$( function() { $(function () {
var keys = []; var keys = [];
var pattern = "71,85,89,71,85,89"; var pattern = "71,85,89,71,85,89";
$(document).keydown(function (e) { $(document).keydown(function (e) {
keys.push(e.keyCode); keys.push(e.keyCode);
if (keys.toString()==pattern) { if (keys.toString() == pattern) {
keys = []; keys = [];
$("#user_profile_pictures_bigone img").attr("src", "{{ static('core/img/yug.jpg') }}"); $("#user_profile_pictures_bigone img").attr("src", "{{ static('core/img/yug.jpg') }}");
} }
if (keys.length==6) { if (keys.length == 6) {
keys.shift(); keys.shift();
} }
});
}); });
} ); $(function () {
$(function(){ $("#user_profile_pictures_thumbnails img").click(function () {
$("#user_profile_pictures_thumbnails img").click(function () { $("#user_profile_pictures_bigone img").attr("src", $(this)[0].src);
$("#user_profile_pictures_bigone img").attr("src", $(this)[0].src); $("#user_profile_pictures_bigone img").attr("alt", $(this)[0].alt);
$("#user_profile_pictures_bigone img").attr("alt", $(this)[0].alt); $("#user_profile_pictures_bigone img").attr("title", $(this)[0].title);
$("#user_profile_pictures_bigone img").attr("title", $(this)[0].title); })
}) });
}); $(function () {
$(function(){ $("#drop_gifts").accordion({
$("#drop_gifts").accordion({ heightStyle: "content",
heightStyle: "content", collapsible: true,
collapsible: true, active: false
active: false });
}); });
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -1,86 +1,184 @@
{% extends "core/base.jinja" %} {%- extends "core/base.jinja" -%}
{% block title %} {%- block title -%}
{% trans %}Edit user{% endtrans %} {%- trans -%}Edit user{%- endtrans -%}
{% endblock %} {%- endblock -%}
{% block content %} {%- block additional_css -%}
<h2>{% trans %}Edit user profile{% endtrans %}</h2> <link rel="stylesheet" href="{{ scss('user/user_edit.scss') }}">
{%- endblock -%}
{%- block content -%}
<h2 class="title">{%- trans -%}Edit user profile{%- endtrans -%}</h2>
<form action="" method="post" enctype="multipart/form-data" id="user_edit"> <form action="" method="post" enctype="multipart/form-data" id="user_edit">
{% csrf_token %}
{%- csrf_token -%}
{{ form.non_field_errors() }} {{ form.non_field_errors() }}
{% for field in form %}
<p>{{ field.errors }}<label for="{{ field.name }}">{{ field.label }} {# User Pictures #}
{%- if field.name == "profile_pict" -%} <div class="profile-pictures">
<br>{% trans %}Current profile: {% endtrans %} <div class="profile-picture">
{% if form.instance.profile_pict %} <div class="profile-picture-display">
<img src="{{ form.instance.profile_pict.get_download_url() }}" title="{% trans %}Profile{% endtrans %}" /><br>
{% if user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) %} {%- if form.instance.profile_pict -%}
<a href="{{ url('core:file_delete', file_id=form.instance.profile_pict.id, popup="") }}">{% trans %}Delete{% endtrans %}</a> <img src="{{ form.instance.profile_pict.get_download_url() }}"
{% endif %} alt="{%- trans -%}Profile{%- endtrans -%}" title="{%- trans -%}Profile{%- endtrans -%}" />
{% else %} {%- else -%}
<img src="{{ static('core/img/unknown.jpg') }}" title="-" crossOrigin="Anonymous" id="new_profile"/><br> <img src="{{ static('core/img/unknown.jpg') }}" alt="{%- trans -%}Profile{%- endtrans -%}"
<div id="take_picture"> title="{%- trans -%}Profile{%- endtrans -%}" />
<div id="camera_canvas" style="width:320; height:240; margin: 0px auto;"></div> {%- endif -%}
<a href="javascript:void(take_snapshot())">{% trans %}Take picture{% endtrans %}</a> </div>
<div class="profile-picture-edit">
<p>{{ form["profile_pict"].label }}</p>
{{ form["profile_pict"] }}
{%- if user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) and form.instance.profile_pict.id -%}
<a href="{{ url('core:file_delete', file_id=form.instance.profile_pict.id, popup='') }}">
{%- trans -%}Delete{%- endtrans -%}
</a>
{%- endif -%}
</div>
</div>
<div class="profile-picture">
<div class="profile-picture-display">
{%- if form.instance.avatar_pict -%}
<img src="{{ form.instance.avatar_pict.get_download_url() }}" alt="{%- trans -%}Profile{%- endtrans -%}"
title="{%- trans -%}Profile{%- endtrans -%}" />
{%- else -%}
<img src="{{ static('core/img/unknown.jpg') }}" alt="{%- trans -%}Profile{%- endtrans -%}"
title="{%- trans -%}Profile{%- endtrans -%}" />
{%- endif -%}
</div>
<div class="profile-picture-edit">
<p>{{ form["avatar_pict"].label }}</p>
{{ form["avatar_pict"] }}
{%- if user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) and form.instance.avatar_pict.id -%}
<a href="{{ url('core:file_delete', file_id=form.instance.avatar_pict.id, popup='') }}">
{%- trans -%}Delete{%- endtrans -%}
</a>
{%- endif -%}
</div>
</div>
<div class="profile-picture">
<div class="profile-picture-display">
{%- if form.instance.scrub_pict -%}
<img src="{{ form.instance.scrub_pict.get_download_url() }}" alt="{%- trans -%}Profile{%- endtrans -%}"
title="{%- trans -%}Profile{%- endtrans -%}" />
{%- else -%}
<img src="{{ static('core/img/unknown.jpg') }}" alt="{%- trans -%}Profile{%- endtrans -%}"
title="{%- trans -%}Profile{%- endtrans -%}" />
{%- endif -%}
</div>
<div class="profile-picture-edit">
<p>{{ form["scrub_pict"].label }}</p>
{{ form["scrub_pict"] }}
{%- if user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) and form.instance.scrub_pict.id -%}
<a href="{{ url('core:file_delete', file_id=form.instance.scrub_pict.id, popup='') }}">
{%- trans -%}Delete{%-endtrans -%}
</a>
{%- endif -%}
</div>
</div>
</div> </div>
{# All fields #}
<div class="profile-fields">
{%- for field in form -%}
{%-
if field.name in ["quote","profile_pict","avatar_pict","scrub_pict","is_subscriber_viewable","forum_signature"]
-%}
{%- continue -%}
{%- endif -%}
<div class="profile-field">
<div class="profile-field-label">{{ field.label }}</div>
<div class="profile-field-content">
{{ field }}
{%- if field.errors -%}
<div class="field-error">{{ field.errors }}</div>
{%- endif -%}
</div>
</div>
{%- endfor -%}
</div>
{# Textareas #}
<div class="profile-fields">
{%- for field in [form["quote"], form["forum_signature"]] -%}
<div class="profile-field">
<div class="profile-field-label">{{ field.label }}</div>
<div class="profile-field-content">
{{ field }}
{%- if field.errors -%}
<div class="field-error">{{ field.errors }}</div>
{%- endif -%}
</div>
</div>
{%- endfor -%}
</div>
{# Checkboxes #}
<div class="profile-visible">
{{ form["is_subscriber_viewable"] }}
{{ form["is_subscriber_viewable"].label }}
</div>
{%- if form.instance == user -%}
<p> <p>
{% endif %}<br> <a href="{{ url('core:password_change') }}">{%- trans -%}Change my password{%- endtrans -%}</a>
{%- elif field.name == "avatar_pict" and form.instance.avatar_pict -%} </p>
<br>{% trans %}Current avatar: {% endtrans %} {%- elif user.is_root -%}
<img src="{{ form.instance.avatar_pict.get_download_url() }}" title="{% trans %}Avatar{% endtrans %}" /><br> <p>
{%- elif field.name == "scrub_pict" and form.instance.scrub_pict -%} <a href="{{ url('core:password_root_change', user_id=form.instance.id) }}">{%- trans -%}Change user password{%-
<br>{% trans %}Current scrub: {% endtrans %} endtrans -%}</a>
<img src="{{ form.instance.scrub_pict.get_download_url() }}" title="{% trans %}Scrub{% endtrans %}" /><br> </p>
{%- endif %}</label> {{ field }}</p> {%- endif -%}
{% endfor %}
<p><input type="submit" value="{% trans %}Update{% endtrans %}" /></p> <p>
<p>{% trans %}Username: {% endtrans %}{{ form.instance.username }}</p> <input type="submit" value="{%- trans -%}Update{%- endtrans -%}" />
{% if form.instance.customer %} </p>
<p>{% trans %}Account number: {% endtrans %}{{ form.instance.customer.account_id }}</p>
{% endif %}
{% if form.instance == user %}
<p><a href="{{ url('core:password_change') }}">{% trans %}Change my password{% endtrans %}</a></p>
{% elif user.is_root %}
<p><a href="{{ url('core:password_root_change', user_id=form.instance.id) }}">{% trans %}Change user password{% endtrans %}</a></p>
{% endif %}
</form> </form>
{% endblock %}
{% block script %}
{{ super() }}
{% if not form.instance.profile_pict %}
<script src="{{ static('core/js/webcam.js') }}"></script>
<script language="JavaScript">
Webcam.on('error', function(msg) { console.log('Webcam.js error: ' + msg) })
Webcam.set({
width: 320,
height: 240,
dest_width: 320,
dest_height: 240,
image_format: 'jpeg',
jpeg_quality: 90,
force_flash: false
});
Webcam.attach( '#camera_canvas' );
function take_snapshot() {
var data_uri = Webcam.snap();
var url = "{{ url('core:user_profile_upload', user_id=form.instance.id) }}";
Webcam.upload( data_uri, url, function(code, text) {
if (code == 302 || code == 200) {
$('#new_profile').attr('src', data_uri);
$('#take_picture').remove();
$('#id_profile_pict').remove();
} else {
console.log("Unknown error: ");
console.log(text);
}
}, "new_profile_pict", {name: 'csrfmiddlewaretoken', value: '{{ csrf_token }}'});
}
</script>
{% endif %}
{% endblock %}
<p>
<em>{%- trans -%}Username: {%- endtrans -%}&nbsp;{{ form.instance.username }}</em>
<br />
{%- if form.instance.customer -%}
<em>{%- trans -%}Account number: {%- endtrans -%}&nbsp;{{ form.instance.customer.account_id }}</em>
{%- endif -%}
</p>
{%- endblock -%}
{%- block script -%}
{{ super() }}
{%- if not form.instance.profile_pict -%}
<script src="{{ static('core/js/webcam.js') }}"></script>
<script>
Webcam.on('error', function (msg) { console.log('Webcam.js error: ' + msg) })
Webcam.set({
width: 320,
height: 240,
dest_width: 320,
dest_height: 240,
image_format: 'jpeg',
jpeg_quality: 90,
force_flash: false
});
Webcam.attach('#camera_canvas');
function take_snapshot() {
const data_uri = Webcam.snap();
const url = "{{ url('core:user_profile_upload', user_id=form.instance.id) }}";
Webcam.upload(data_uri, url, function (code, text) {
if (code === 302 || code === 200) {
$('#new_profile').attr('src', data_uri);
$('#take_picture').remove();
$('#id_profile_pict').remove();
} else {
console.log("Unknown error: ");
console.log(text);
}
}, "new_profile_pict", { name: 'csrfmiddlewaretoken', value: '{{ csrf_token }}' });
}
</script>
{%- endif -%}
{%- endblock -%}

View File

@ -1,45 +1,67 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% from "core/macros.jinja" import user_link_with_pict, delete_godfather %} {% from "core/macros.jinja" import user_link_with_pict, delete_godfather %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('user/user_godfathers.scss') }}">
{%- endblock -%}
{% block title %} {% block title %}
{% trans user_name=profile.get_display_name() %}{{ user_name }}'s family{% endtrans %} {% trans user_name=profile.get_display_name() %}{{ user_name }}'s family{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<p><a href="{{ url("core:user_godfathers_tree_pict", user_id=profile.id) }}?family"> <div class="container">
{% trans %}Show family picture{% endtrans %}</a></p> <a href="{{ url('core:user_godfathers_tree_pict', user_id=profile.id) }}?family">
{% trans %}Show family picture{% endtrans %}
</a>
<h4>{% trans %}Godfathers / Godmothers{% endtrans %}</h4>
{% if profile.godfathers.exists() %} {% if profile.godfathers.exists() %}
<h4>{% trans %}Godfathers / Godmothers{% endtrans %}</h4> <ul class="users">
<ul>
{% for u in profile.godfathers.all() %} {% for u in profile.godfathers.all() %}
<li> <a href="{{ url("core:user_godfathers", user_id=u.id) }}" class="mini_profile_link" > <li class="users-card">
{{ u.get_mini_item()|safe }} </a>{{ delete_godfather(user, profile, u, True) }}</li> <a href="{{ url('core:user_godfathers', user_id=u.id) }}" class="mini_profile_link">
{{ u.get_mini_item() | safe }}
</a>
{{ delete_godfather(user, profile, u, True) }}
</li>
{% endfor %} {% endfor %}
</ul> </ul>
<p><a href="{{ url("core:user_godfathers_tree", user_id=profile.id) }}">
{% trans %}Show ancestors tree{% endtrans %}</a></p> <a href="{{ url('core:user_godfathers_tree', user_id=profile.id) }}">
{% trans %}Show ancestors tree{% endtrans %}
</a>
{% else %} {% else %}
<p>{% trans %}No godfathers / godmothers{% endtrans %} <p>{% trans %}No godfathers / godmothers{% endtrans %}
{% endif %} {% endif %}
<h4>{% trans %}Godchildren{% endtrans %}</h4>
{% if profile.godchildren.exists() %} {% if profile.godchildren.exists() %}
<h4>{% trans %}Godchildren{% endtrans %}</h4> <ul class="users">
<ul>
{% for u in profile.godchildren.all() %} {% for u in profile.godchildren.all() %}
<li> <a href="{{ url("core:user_godfathers", user_id=u.id) }}" class="mini_profile_link" > <li class="users-card">
{{ u.get_mini_item()|safe }} </a>{{ delete_godfather(user, profile, u, False) }}</li> <a href="{{ url('core:user_godfathers', user_id=u.id) }}" class="mini_profile_link">
{{ u.get_mini_item()|safe }}
</a>
{{ delete_godfather(user, profile, u, False) }}
</li>
{% endfor %} {% endfor %}
</ul> </ul>
<p><a href="{{ url("core:user_godfathers_tree", user_id=profile.id) }}?descent">
{% trans %}Show descent tree{% endtrans %}</a></p> <a href="{{ url('core:user_godfathers_tree', user_id=profile.id) }}?descent">
{% trans %}Show descent tree{% endtrans %}
</a>
{% else %} {% else %}
<p>{% trans %}No godchildren{% endtrans %} <p>{% trans %}No godchildren{% endtrans %}
{% endif %} {% endif %}
{% if profile == user or user.is_root %}
{% if profile == user or user.is_root %}
<form action="" method="post"> <form action="" method="post">
{% csrf_token %} {% csrf_token %}
{{ form.as_p() }} {{ form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form> </form>
{% endif %} {% endif %}
</div>
{% endblock %} {% endblock %}

View File

@ -1,14 +1,16 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('user/user_group.scss') }}">
{%- endblock -%}
{% block content %} {% block content %}
<h2>{% trans user_name=profile.get_full_name() %}Edit user groups for {{ user_name }}{% endtrans %}</h2> <main>
<form action="" method="post"> <h2>{% trans user_name=profile.get_full_name() %}Edit user groups for {{ user_name }}{% endtrans %}</h2>
{% csrf_token %} <form action="" method="post">
{{ form.as_p() }} {% csrf_token %}
<p><input type="submit" value="{% trans %}Update{% endtrans %}" /></p> {{ form.as_p() }}
</form> <p><input type="submit" value="{% trans %}Update{% endtrans %}" /></p>
{% endblock %} </form>
</main>
{%- endblock -%}

View File

@ -1,26 +1,48 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('sas/album.scss') }}">
{%- endblock -%}
{% block title %} {% block title %}
{% trans user_name=profile.get_display_name() %}{{ user_name }}'s pictures{% endtrans %} {% trans user_name=profile.get_display_name() %}{{ user_name }}'s pictures{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<main>
{% if can_edit(profile, user) %} {% if can_edit(profile, user) %}
<button id="download_all_pictures", onclick=download_pictures()>{% trans %}Download all my pictures{% endtrans %}</button> <button id="download_all_pictures", onclick=download_pictures()>{% trans %}Download all my pictures{% endtrans %}</button>
{% endif %} {% endif %}
{% for a in albums %} {% for a in albums %}
<div style="padding: 10px">
<h4>{{ a.name }}</h4> <h4>{{ a.name }}</h4>
<hr> <div class="photos">
{% for picture in pictures[a.id] %} {% for p in pictures[a.id] %}
<div class="picture"> {% if p.can_be_viewed_by(user) %}
<a href="{{ url("sas:picture", picture_id=picture.id) }}#pict"> <a href="{{ url("sas:picture", picture_id=p.id) }}#pict">
<img src="{{ picture.get_download_thumb_url() }}" alt="{{ picture.get_display_name() }}" style="max-width: 100%" loading="lazy"/> <div
</a> class="photo{% if not p.is_moderated %} not_moderated{% endif %}"
style="background-image: url('{% if p.file %}{{ p.get_download_url() }}{% else %}{{ static('core/img/sas.jpg') }}{% endif %}');"
>
{% if not p.is_moderated %}
<div class="overlay">&nbsp;</div>
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
{% else %}
<div class="text">&nbsp;</div>
{% endif %}
</div>
</a>
{% else %}
<div>
<div class="photo">
<div class="text">{% trans %}Picture Unavailable{% endtrans %}</div>
</div>
</div>
{% endif %}
{% endfor %}
</div> </div>
<br>
{% endfor %} {% endfor %}
</div> </main>
{% endfor %}
{% endblock %} {% endblock %}
{% block script %} {% block script %}

View File

@ -1,46 +1,69 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('user/user_preferences.scss') }}">
{%- endblock -%}
{% block title %} {% block title %}
{% trans %}Preferences{% endtrans %} {% trans %}Preferences{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<h2>{% trans %}Preferences{% endtrans %}</h2> <div class="main">
<form action="" method="post" enctype="multipart/form-data"> <h2>{% trans %}Preferences{% endtrans %}</h2>
{% csrf_token %} <h3>{% trans %}General{% endtrans %}</h3>
{{ form.as_p() }} <form class="form form-general" action="" method="post" enctype="multipart/form-data">
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> {% csrf_token %}
</form> {{ form.as_p() }}
<h4>{% trans %}Trombi{% endtrans %}</h4> <input class="form-submit-btn" type="submit" value="{% trans %}Save{% endtrans %}" />
{% if trombi_form %} </form>
<form action="{{ url('trombi:user_tools') }}" method="post" enctype="multipart/form-data">
{% csrf_token %} <h3>{% trans %}Trombi{% endtrans %}</h3>
{{ trombi_form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> {% if trombi_form %}
</form> <form class="form form-trombi" action="{{ url('trombi:user_tools') }}" method="post" enctype="multipart/form-data">
{% else %} {% csrf_token %}
<p>{% trans trombi=user.trombi_user.trombi %}You already choose to be in that Trombi: {{ trombi }}.{% endtrans %} {{ trombi_form.as_p() }}
<a href="{{ url('trombi:user_tools') }}">{% trans %}Go to my Trombi tools{% endtrans %}</a></p> <input class="form-submit-btn" type="submit" value="{% trans %}Save{% endtrans %}" />
{% endif %} </form>
{% if profile.customer %}
<h4>{% trans %}Student cards{% endtrans %}</h4> {% else %}
<p>{% trans %}You can add a card by asking at a counter or add it yourself here. If you want to manually add a student card yourself, you'll need a NFC reader. We store the UID of the card which is 14 characters long.{% endtrans %}</p> <p>{% trans trombi=user.trombi_user.trombi %}You already choose to be in that Trombi: {{ trombi }}.{% endtrans %}
<form action="{{ url('counter:add_student_card', customer_id=profile.customer.pk) }}" method="post"> <br />
{% csrf_token %} <a href="{{ url('trombi:user_tools') }}">{% trans %}Go to my Trombi tools{% endtrans %}</a>
{{ student_card_form.as_p() }} </p>
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> {% endif %}
</form>
{% if profile.customer.student_cards.exists() %}
<ul>
{% for card in profile.customer.student_cards.all() %}
<li>{{ card.uid }} - <a href="{{ url('counter:delete_student_card', customer_id=profile.customer.pk, card_id=card.id) }}">{% trans %}Delete{% endtrans %}</a></li>
{% endfor %}
</ul>
{% else %}
<p>{% trans %}No student cards registered.{% endtrans %}</p>
{% endif %}
{% endif %}
{% endblock %}
{% if profile.customer %}
<h3>{% trans %}Student cards{% endtrans %}</h3>
{% if profile.customer.student_cards.exists() %}
<ul class="student-cards">
{% for card in profile.customer.student_cards.all() %}
<li>
{{ card.uid }}
&nbsp;-&nbsp;
<a href="{{ url('counter:delete_student_card', customer_id=profile.customer.pk, card_id=card.id) }}">
{% trans %}Delete{% endtrans %}
</a>
</li>
{% endfor %}
</ul>
{% else %}
<em class="no-cards">{% trans %}No student card registered.{% endtrans %}</em>
<p class="justify">
{% trans %}You can add a card by asking at a counter or add it yourself here. If you want to manually
add a student card yourself, you'll need a NFC reader. We store the UID of the card which is 14 characters long.{% endtrans %}
</p>
{% endif %}
<form class="form form-cards" action="{{ url('counter:add_student_card', customer_id=profile.customer.pk) }}"
method="post">
{% csrf_token %}
{{ student_card_form.as_p() }}
<input class="form-submit-btn" type="submit" value="{% trans %}Save{% endtrans %}" />
</form>
{% endif %}
</div>
{% endblock %}

View File

@ -1,25 +1,41 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('user/user_stats.scss') }}">
{%- endblock -%}
{% block title %} {% block title %}
{% trans user_name=profile.get_display_name() %}{{ user_name }}'s stats{% endtrans %} {% trans user_name=profile.get_display_name() %}{{ user_name }}'s stats{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="container">
<div class="row">
{% if profile.permanencies %} {% if profile.permanencies %}
<h3>{% trans %}Permanencies{% endtrans %}</h3>
<div> <div>
<p>Total: {{ total_perm_time }}</p> <h3>{% trans %}Permanencies{% endtrans %}</h3>
<p>Foyer: {{ total_foyer_time }}</p> <div class="flexed">
<p>MDE: {{ total_mde_time }}</p> <div><span>Foyer :</span><span>{{ total_foyer_time }}</span></div>
<p>La Gommette: {{ total_gommette_time }}</p> <div><span>Gommette :</span><span>{{ total_gommette_time }}</span></div>
<div><span>MDE :</span><span>{{ total_mde_time }}</span></div>
<div><b>Total :</b><b>{{ total_perm_time }}</b></div>
</div>
</div> </div>
{% endif %} {% endif %}
<h3>{% trans %}Buyings{% endtrans %}</h3>
<div> <div>
<p>Foyer: {{ total_foyer_buyings }} €</p> <h3>{% trans %}Buyings{% endtrans %}</h3>
<p>MDE: {{ total_mde_buyings }} €</p> <div class="flexed">
<p>La Gommette: {{ total_gommette_buyings }} €</p> <div><span>Foyer :</span><span>{{ total_foyer_buyings }}&nbsp;€</span></div>
<div><span>Gommette :</span><span>{{ total_gommette_buyings }}&nbsp;€</span></div>
<div><span>MDE :</span><span>{{ total_mde_buyings }}&nbsp;€</span></div>
<div><b>Total :</b><b>{{ total_foyer_buyings + total_gommette_buyings + total_mde_buyings }}&nbsp;€</b>
</div>
</div>
</div> </div>
</div>
<div>
<h3>{% trans %}Product top 10{% endtrans %}</h3> <h3>{% trans %}Product top 10{% endtrans %}</h3>
<table> <table>
<thead> <thead>
@ -29,14 +45,14 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for p in top_product %} {% for p in top_product %}
<tr> <tr>
<td>{{ p['product__name'] }}</td> <td>{{ p['product__name'] }}</td>
<td>{{ p['product_sum'] }}</td> <td>{{ p['product_sum'] }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% endblock %} </div>
</div>
{% endblock %}

View File

@ -1,137 +1,176 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('user/user_tools.scss') }}">
{%- endblock -%}
{% block title %} {% block title %}
{% trans user_name=user.get_display_name() %}{{ user_name }}'s tools{% endtrans %} {% trans user_name=user.get_display_name() %}{{ user_name }}'s tools{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<h3>{% trans %}User Tools{% endtrans %}</h3> <main>
<h3>{% trans %}User Tools{% endtrans %}</h3>
<hr> <div class="container">
<h4>{% trans %}Sith management{% endtrans %}</h4> {% if user.can_create_subscription or user.is_root or user.is_board_member %}
<ul> <div>
{% if user.is_root %} <h4>{% trans %}Sith management{% endtrans %}</h4>
<li><a href="{{ url('core:group_list') }}">{% trans %}Groups{% endtrans %}</a></li> <ul>
<li><a href="{{ url('rootplace:merge') }}">{% trans %}Merge users{% endtrans %}</a></li> {% if user.is_root %}
<li><a href="{{ url('rootplace:operation_logs') }}">{% trans %}Operation logs{% endtrans %}</a></li> <li><a href="{{ url('core:group_list') }}">{% trans %}Groups{% endtrans %}</a></li>
<li><a href="{{ url('rootplace:delete_forum_messages') }}">{% trans %}Delete user's forum messages{% endtrans %}</a></li> <li><a href="{{ url('rootplace:merge') }}">{% trans %}Merge users{% endtrans %}</a></li>
{% endif %} <li><a href="{{ url('rootplace:operation_logs') }}">{% trans %}Operation logs{% endtrans %}</a></li>
{% if user.can_create_subscription or user.is_root %} <li><a href="{{ url('rootplace:delete_forum_messages') }}">{% trans %}Delete user's forum messages{% endtrans %}</a></li>
<li><a href="{{ url('subscription:subscription') }}">{% trans %}Subscriptions{% endtrans %}</a></li> {% endif %}
{% endif %} {% if user.can_create_subscription or user.is_root %}
{% if user.is_board_member or user.is_root %} <li><a href="{{ url('subscription:subscription') }}">{% trans %}Subscriptions{% endtrans %}</a></li>
<li><a href="{{ url('subscription:stats') }}">{% trans %}Subscription stats{% endtrans %}</a></li> {% endif %}
<li><a href="{{ url('club:club_new') }}">{% trans %}New club{% endtrans %}</a></li> {% if user.is_board_member or user.is_root %}
{% endif %} <li><a href="{{ url('subscription:stats') }}">{% trans %}Subscription stats{% endtrans %}</a></li>
</ul> <li><a href="{{ url('club:club_new') }}">{% trans %}New club{% endtrans %}</a></li>
{% endif %}
<hr> </ul>
<h4>{% trans %}Counters{% endtrans %}</h4> </div>
<ul>
{% if user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID) or user.is_root %}
<li><a href="{{ url('counter:admin_list') }}">{% trans %}General counters management{% endtrans %}</a></li>
<li><a href="{{ url('counter:product_list') }}">{% trans %}Products management{% endtrans %}</a></li>
<li><a href="{{ url('counter:producttype_list') }}">{% trans %}Product types management{% endtrans %}</a></li>
<li><a href="{{ url('counter:cash_summary_list') }}">{% trans %}Cash register summaries{% endtrans %}</a></li>
<li><a href="{{ url('counter:invoices_call') }}">{% trans %}Invoices call{% endtrans %}</a></li>
<li><a href="{{ url('counter:eticket_list') }}">{% trans %}Etickets{% endtrans %}</a></li>
{% endif %}
{% for b in settings.SITH_COUNTER_BARS %}
{% if user.is_in_group(b[1]+" admin") %}
<li>
<a href="{{ url('counter:details', counter_id=b[0]) }}">{{ b[1] }}</a> -
<a href="{{ url('counter:admin', counter_id=b[0]) }}">{% trans %}Edit{% endtrans %}</a> -
<a href="{{ url('counter:stats', counter_id=b[0]) }}">{% trans %}Stats{% endtrans %}</a> -
{% set c = Counter.objects.filter(id=b[0]).first() %}
{% if c.stock %}
<a href="{{ url('stock:items_list', stock_id=c.stock.id)}}">Stock</a> -
<a href="{{ url('stock:shoppinglist_list', stock_id=c.stock.id)}}">{% trans %}Shopping lists{% endtrans %}</a>
{% else %}
<a href="{{url('stock:new', counter_id=c.id)}}">{% trans %}Create new stock{% endtrans%}</a>
{% endif %} {% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
<hr> {% set is_admin_on_a_counter = false %}
<h4>{% trans %}Accounting{% endtrans %}</h4> {% for b in settings.SITH_COUNTER_BARS if user.is_in_group(b[1] + " admin") %}
<ul> {% set is_admin_on_a_counter = true %}
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) or user.is_root %} {% endfor %}
<li><a href="{{ url('accounting:refound_account') }}">{% trans %}Refound Account{% endtrans %}</a></li>
<li><a href="{{ url('accounting:bank_list') }}">{% trans %}General accounting{% endtrans %}</a></li>
<li><a href="{{ url('accounting:co_list') }}">{% trans %}Company list{% endtrans %}</a></li>
{% endif %}
{% for m in user.memberships.filter(end_date=None).filter(role__gte=7).all() -%}
{%- for b in m.club.bank_accounts.all() %}
<li><strong>{% trans %}Bank account: {% endtrans %}</strong>
<a href="{{ url('accounting:bank_details', b_account_id=b.id) }}">{{ b }}</a></li>
{%- endfor %}
{% if m.club.club_account.exists() -%}
{% for ca in m.club.club_account.all() %}
<li><strong>{% trans %}Club account: {% endtrans %}</strong> <a href="{{ url('accounting:club_details', c_account_id=ca.id) }}">{{ ca }}</a></li>
{%- endfor %}
{%- endif -%}
{%- endfor %}
</ul>
<hr> {% if
<h4>{% trans %}Communication{% endtrans %}</h4> user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID) or user.is_root
<ul> or is_admin_on_a_counter
{% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or user.is_root %} %}
<li><a href="{{ url('com:weekmail_article') }}">{% trans %}Create weekmail article{% endtrans %}</a></li> <div>
<li><a href="{{ url('com:weekmail') }}">{% trans %}Weekmail{% endtrans %}</a></li> <h4>{% trans %}Counters{% endtrans %}</h4>
<li><a href="{{ url('com:weekmail_destinations') }}">{% trans %}Weekmail destinations{% endtrans %}</a></li> <ul>
<li><a href="{{ url('com:news_new') }}">{% trans %}Create news{% endtrans %}</a></li> {% if user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID) or user.is_root %}
<li><a href="{{ url('com:news_admin_list') }}">{% trans %}Moderate news{% endtrans %}</a></li> <li><a href="{{ url('counter:admin_list') }}">{% trans %}General counters management{% endtrans %}</a></li>
<li><a href="{{ url('com:alert_edit') }}">{% trans %}Edit alert message{% endtrans %}</a></li> <li><a href="{{ url('counter:product_list') }}">{% trans %}Products management{% endtrans %}</a></li>
<li><a href="{{ url('com:info_edit') }}">{% trans %}Edit information message{% endtrans %}</a></li> <li><a href="{{ url('counter:producttype_list') }}">{% trans %}Product types management{% endtrans %}</a></li>
<li><a href="{{ url('core:file_moderation') }}">{% trans %}Moderate files{% endtrans %}</a></li> <li><a href="{{ url('counter:cash_summary_list') }}">{% trans %}Cash register summaries{% endtrans %}</a></li>
<li><a href="{{ url('com:mailing_admin') }}">{% trans %}Mailing lists administration{% endtrans %}</a></li> <li><a href="{{ url('counter:invoices_call') }}">{% trans %}Invoices call{% endtrans %}</a></li>
<li><a href="{{ url('com:poster_list') }}">{% trans %}Posters{% endtrans %}</a></li> <li><a href="{{ url('counter:eticket_list') }}">{% trans %}Etickets{% endtrans %}</a></li>
<li><a href="{{ url('com:screen_list') }}">{% trans %}Screens{% endtrans %}</a></li> {% endif %}
{% endif %} {% for b in settings.SITH_COUNTER_BARS %}
{% if user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %} {% if user.is_in_group(b[1]+" admin") %}
<li><a href="{{ url('sas:moderation') }}">{% trans %}Moderate pictures{% endtrans %}</a></li> <li>
{% endif %} <a href="{{ url('counter:details', counter_id=b[0]) }}">{{ b[1] }}</a> -
</ul> <a href="{{ url('counter:admin', counter_id=b[0]) }}">{% trans %}Edit{% endtrans %}</a> -
<a href="{{ url('counter:stats', counter_id=b[0]) }}">{% trans %}Stats{% endtrans %}</a> -
{% set c = Counter.objects.filter(id=b[0]).first() %}
{% if c.stock %}
<a href="{{ url('stock:items_list', stock_id=c.stock.id)}}">Stock</a> -
<a href="{{ url('stock:shoppinglist_list', stock_id=c.stock.id)}}">{% trans %}Shopping lists{% endtrans %}</a>
{% else %}
<a href="{{url('stock:new', counter_id=c.id)}}">{% trans %}Create new stock{% endtrans%}</a>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endif %}
{% if
user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) or user.is_root
or user.memberships.filter(end_date=None).filter(role__gte=7).all() | length > 10
%}
<div>
<h4>{% trans %}Accounting{% endtrans %}</h4>
<ul>
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) or user.is_root %}
<li><a href="{{ url('accounting:refound_account') }}">{% trans %}Refound Account{% endtrans %}</a></li>
<li><a href="{{ url('accounting:bank_list') }}">{% trans %}General accounting{% endtrans %}</a></li>
<li><a href="{{ url('accounting:co_list') }}">{% trans %}Company list{% endtrans %}</a></li>
{% endif %}
<hr> {% for m in user.memberships.filter(end_date=None).filter(role__gte=7).all() -%}
<h4>{% trans %}Club tools{% endtrans %}</h4> {%- for b in m.club.bank_accounts.all() %}
<ul> <li>
{% for m in user.memberships.filter(end_date=None).all() %} <strong>{% trans %}Bank account: {% endtrans %}</strong>
<li><a href="{{ url('club:tools', club_id=m.club.id) }}">{{ m.club }}</a></li> <a href="{{ url('accounting:bank_details', b_account_id=b.id) }}">{{ b }}</a>
{% endfor %} </li>
</ul> {%- endfor %}
<hr> {% if m.club.club_account.exists() -%}
<h4>{% trans %}Pedagogy{% endtrans %}</h4> {% for ca in m.club.club_account.all() %}
<ul> <li>
{% if user.is_in_group(settings.SITH_GROUP_PEDAGOGY_ADMIN_ID) or user.is_root %} <strong>{% trans %}Club account: {% endtrans %}</strong>
<li><a href="{{ url('pedagogy:uv_create') }}">{% trans %}Create UV{% endtrans %}</a></li> <a href="{{ url('accounting:club_details', c_account_id=ca.id) }}">{{ ca }}</a>
<li><a href="{{ url('pedagogy:moderation') }}">{% trans %}Moderate comments{% endtrans %}</a></li> </li>
{% endif %} {%- endfor %}
</ul> {%- endif -%}
{%- endfor %}
</ul>
</div>
{% endif %}
<hr> {% if user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or user.is_root %}
<h4>{% trans %}Elections{% endtrans %}</h4> <div>
<ul> <h4>{% trans %}Communication{% endtrans %}</h4>
<li><a href="{{ url('election:list') }}">{% trans %}See available elections{% endtrans %}</a></li> <ul>
<li><a href="{{ url('election:list_archived') }}">{% trans %}See archived elections{% endtrans %}</a></li> {% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or user.is_root %}
{%- if user.is_subscribed -%} <li><a href="{{ url('com:weekmail_article') }}">{% trans %}Create weekmail article{% endtrans %}</a></li>
<li><a href="{{ url('election:create') }}">{% trans %}Create a new election{% endtrans %}</a></li> <li><a href="{{ url('com:weekmail') }}">{% trans %}Weekmail{% endtrans %}</a></li>
{%- endif -%} <li><a href="{{ url('com:weekmail_destinations') }}">{% trans %}Weekmail destinations{% endtrans %}</a></li>
</ul> <li><a href="{{ url('com:news_new') }}">{% trans %}Create news{% endtrans %}</a></li>
<li><a href="{{ url('com:news_admin_list') }}">{% trans %}Moderate news{% endtrans %}</a></li>
<li><a href="{{ url('com:alert_edit') }}">{% trans %}Edit alert message{% endtrans %}</a></li>
<li><a href="{{ url('com:info_edit') }}">{% trans %}Edit information message{% endtrans %}</a></li>
<li><a href="{{ url('core:file_moderation') }}">{% trans %}Moderate files{% endtrans %}</a></li>
<li><a href="{{ url('com:mailing_admin') }}">{% trans %}Mailing lists administration{% endtrans %}</a></li>
<li><a href="{{ url('com:poster_list') }}">{% trans %}Posters{% endtrans %}</a></li>
<li><a href="{{ url('com:screen_list') }}">{% trans %}Screens{% endtrans %}</a></li>
{% endif %}
{% if user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %}
<li><a href="{{ url('sas:moderation') }}">{% trans %}Moderate pictures{% endtrans %}</a></li>
{% endif %}
</ul>
</div>
{% endif %}
<hr> {% if user.memberships.filter(end_date=None).all().count() > 0 %}
<h4>{% trans %}Other tools{% endtrans %}</h4> <div>
<ul> <h4>{% trans %}Club tools{% endtrans %}</h4>
<li><a href="{{ url('core:to_markdown') }}">{% trans %}Convert dokuwiki/BBcode syntax to Markdown{% endtrans %}</a></li> <ul>
<li><a href="{{ url('trombi:user_tools') }}">{% trans %}Trombi tools{% endtrans %}</a></li> {% for m in user.memberships.filter(end_date=None).all() %}
</ul> <li><a href="{{ url('club:tools', club_id=m.club.id) }}">{{ m.club }}</a></li>
{% endfor %}
{% endblock %} </ul>
</div>
{% endif %}
{% if user.is_in_group(settings.SITH_GROUP_PEDAGOGY_ADMIN_ID) or user.is_root %}
<div>
<h4>{% trans %}Pedagogy{% endtrans %}</h4>
<ul>
<li><a href="{{ url('pedagogy:uv_create') }}">{% trans %}Create UV{% endtrans %}</a></li>
<li><a href="{{ url('pedagogy:moderation') }}">{% trans %}Moderate comments{% endtrans %}</a></li>
</ul>
</div>
{% endif %}
<div>
<h4>{% trans %}Elections{% endtrans %}</h4>
<ul>
<li><a href="{{ url('election:list') }}">{% trans %}See available elections{% endtrans %}</a></li>
<li><a href="{{ url('election:list_archived') }}">{% trans %}See archived elections{% endtrans %}</a></li>
{%- if user.is_subscribed -%}
<li><a href="{{ url('election:create') }}">{% trans %}Create a new election{% endtrans %}</a></li>
{%- endif -%}
</ul>
</div>
<div>
<h4>{% trans %}Other tools{% endtrans %}</h4>
<ul>
<li><a href="{{ url('core:to_markdown') }}">{% trans %}Convert dokuwiki/BBcode syntax to Markdown{% endtrans %}</a></li>
<li><a href="{{ url('trombi:user_tools') }}">{% trans %}Trombi tools{% endtrans %}</a></li>
</ul>
</div>
</div>
</main>
{% endblock %}

View File

@ -272,7 +272,7 @@ class UserRegistrationTest(TestCase):
) )
self.assertTrue(response.status_code == 200) self.assertTrue(response.status_code == 200)
self.assertTrue( self.assertTrue(
"""<p>Votre nom d\\'utilisateur et votre mot de passe ne correspondent pas. Merci de r\\xc3\\xa9essayer.</p>""" """<p class="alert alert-red">Votre nom d\\'utilisateur et votre mot de passe ne correspondent pas. Merci de r\\xc3\\xa9essayer.</p>"""
in str(response.content) in str(response.content)
) )

View File

@ -22,6 +22,7 @@
# #
# #
import subprocess
import re import re
# Image utils # Image utils
@ -37,6 +38,17 @@ from django.conf import settings
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
def get_git_revision_short_hash() -> str:
"""
Return the short hash of the current commit
"""
return (
subprocess.check_output(["git", "rev-parse", "--short", "HEAD"])
.decode("ascii")
.strip()
)
def get_start_of_semester(d=date.today()): def get_start_of_semester(d=date.today()):
""" """
This function computes the start date of the semester with respect to the given date (default is today), This function computes the start date of the semester with respect to the given date (default is today),

View File

@ -250,6 +250,7 @@ class UserProfileForm(forms.ModelForm):
"scrub_pict": forms.ClearableFileInput, "scrub_pict": forms.ClearableFileInput,
"phone": PhoneNumberInternationalFallbackWidget, "phone": PhoneNumberInternationalFallbackWidget,
"parent_phone": PhoneNumberInternationalFallbackWidget, "parent_phone": PhoneNumberInternationalFallbackWidget,
"quote": forms.Textarea,
} }
labels = { labels = {
"profile_pict": _( "profile_pict": _(

View File

@ -5,23 +5,41 @@
{% trans counter_name=counter %}{{ counter_name }} activity{% endtrans %} {% trans counter_name=counter %}{{ counter_name }} activity{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {%- block additional_css -%}
<h3>{% trans counter_name=counter %}{{ counter_name }} activity{% endtrans %}</h3> <link rel="stylesheet" href="{{ scss('counter/activity.scss') }}">
{% if counter.type == 'BAR' %} {%- endblock -%}
<h4>{% trans %}Barmen list{% endtrans %}</h4>
<ul>
{% for b in counter.get_barmen_list() %}
<li>{{ user_profile_link(b) }}</li>
{% endfor %}
</ul>
{% endif %}
<h5>{% trans %}Legend{% endtrans %}</h5> {% block content %}
<span style="color: green">&#x2713;</span> : {% trans %}counter is open, there's at least one barman connected{% endtrans %} <h3>{% trans counter_name=counter %}{{ counter_name }} activity{% endtrans %}</h3>
<br> {% if counter.type == 'BAR' %}
<span style="color: orange">&#x3f;</span> : {% trans minutes=settings.SITH_COUNTER_MINUTE_INACTIVE %}counter is open but not active, the last sale was done at least {{ minutes }} minutes ago {% endtrans %} <h4>{% trans %}Barmen list{% endtrans %}</h4>
<br> <ul>
<span style="color: red">&#10007;</span> : {% trans %}counter is not open : no one is connected{% endtrans %} {% set barmans_list = counter.get_barmen_list() %}
{% if barmans_list | length > 0 %}
{% for b in barmans_list %}
<li>{{ user_profile_link(b) }}</li>
{% endfor %}
{% else %}
{% trans %}There is currently no barman connected.{% endtrans %}
{% endif %}
</ul>
{% endif %}
<h5>{% trans %}Legend{% endtrans %}</h5>
<div class="activity-description">
<div>
<i class="fa fa-check" style="color: #2ecc71"></i>
<span>{% trans %}counter is open, there's at least one barman connected{% endtrans %}</span>
</div>
<div>
<i class="fa fa-question" style="color: #f39c12"></i>
<span>{% trans minutes=settings.SITH_COUNTER_MINUTE_INACTIVE %}counter is open but not active, the last sale was done at least {{ minutes }} minutes ago {% endtrans %}</span>
</div>
<div>
<i class="fa fa-times" style="color: #eb2f06"></i>
<span>{% trans %}counter is not open : no one is connected{% endtrans %}</span>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1641,6 +1641,10 @@ msgstr "Appels affichés"
msgid "Calls to moderate" msgid "Calls to moderate"
msgstr "Appels à modérer" msgstr "Appels à modérer"
#: core/templates/core/base.jinja
msgid "Site version:"
msgstr "Version du site :"
#: com/templates/com/news_admin_list.jinja:242 #: com/templates/com/news_admin_list.jinja:242
#: core/templates/core/base.jinja:183 #: core/templates/core/base.jinja:183
msgid "Events" msgid "Events"
@ -2211,8 +2215,8 @@ msgid "Visitor"
msgstr "Visiteur" msgstr "Visiteur"
#: core/models.py:787 #: core/models.py:787
msgid "do you want to receive the weekmail" msgid "receive the Weekmail"
msgstr "voulez-vous recevoir le Weekmail" msgstr "recevoir le Weekmail"
#: core/models.py:789 #: core/models.py:789
msgid "show your stats to others" msgid "show your stats to others"
@ -2220,11 +2224,11 @@ msgstr "montrez vos statistiques aux autres"
#: core/models.py:791 #: core/models.py:791
msgid "get a notification for every click" msgid "get a notification for every click"
msgstr "recevez une notification pour chaque click" msgstr "avoir une notification pour chaque click"
#: core/models.py:794 #: core/models.py:794
msgid "get a notification for every refilling" msgid "get a notification for every refilling"
msgstr "recevez une notification pour chaque rechargement" msgstr "avoir une notification pour chaque rechargement"
#: core/models.py:817 #: core/models.py:817
msgid "file name" msgid "file name"
@ -2399,7 +2403,7 @@ msgstr "Connexion"
#: core/templates/core/base.jinja:62 core/templates/core/register.jinja:18 #: core/templates/core/base.jinja:62 core/templates/core/register.jinja:18
msgid "Register" msgid "Register"
msgstr "S'enregister" msgstr "Inscription"
#: core/templates/core/base.jinja:91 core/templates/core/base.jinja:92 #: core/templates/core/base.jinja:91 core/templates/core/base.jinja:92
#: forum/templates/forum/macros.jinja:171 #: forum/templates/forum/macros.jinja:171
@ -2559,9 +2563,9 @@ msgstr "Aide & Documentation"
msgid "R&D" msgid "R&D"
msgstr "R&D" msgstr "R&D"
#: core/templates/core/base.jinja:268 #: core/templates/core/base.jinja:262
msgid "Site made by good people" msgid "Site created by the IT Department of the AE"
msgstr "Site réalisé par des gens bons" msgstr "Site réalisé par le Pôle Informatique de l'AE"
#: core/templates/core/create.jinja:4 core/templates/core/create.jinja:8 #: core/templates/core/create.jinja:4 core/templates/core/create.jinja:8
#, python-format #, python-format
@ -2641,6 +2645,11 @@ msgstr "Coller"
msgid "Clipboard: " msgid "Clipboard: "
msgstr "Presse-papier : " msgstr "Presse-papier : "
#: sas/templates/sas/album.jinja:69
#: sas/templates/sas/album.jinja:97
msgid "To be moderated"
msgstr "A modérer"
#: core/templates/core/file_detail.jinja:53 #: core/templates/core/file_detail.jinja:53
msgid "Real name: " msgid "Real name: "
msgstr "Nom réel : " msgstr "Nom réel : "
@ -3323,6 +3332,10 @@ msgstr "Télécharger toutes mes photos"
msgid "Error downloading your pictures" msgid "Error downloading your pictures"
msgstr "Erreur de téléchargement de vos photos" msgstr "Erreur de téléchargement de vos photos"
#: core/templates/core/user_picture.jinja:
msgid "Picture Unavailable"
msgstr "Photo Indisponible"
#: core/templates/core/user_preferences.jinja:4 #: core/templates/core/user_preferences.jinja:4
#: core/templates/core/user_preferences.jinja:8 core/views/user.py:234 #: core/templates/core/user_preferences.jinja:8 core/views/user.py:234
msgid "Preferences" msgid "Preferences"
@ -3357,8 +3370,8 @@ msgstr ""
"14 caractères de long." "14 caractères de long."
#: core/templates/core/user_preferences.jinja:40 #: core/templates/core/user_preferences.jinja:40
msgid "No student cards registered." msgid "No student card registered."
msgstr "Aucune cartes étudiante enregistré." msgstr "Aucune carte étudiante enregistrée."
#: core/templates/core/user_stats.jinja:4 #: core/templates/core/user_stats.jinja:4
#, python-format #, python-format
@ -3981,6 +3994,10 @@ msgstr "Activité sur %(counter_name)s"
msgid "Barmen list" msgid "Barmen list"
msgstr "Barmans" msgstr "Barmans"
#: counter/templates/counter/activity.jinja:23
msgid "There is currently no barman connected."
msgstr "Il n'y a actuellement aucun barman connecté."
#: counter/templates/counter/activity.jinja:19 #: counter/templates/counter/activity.jinja:19
msgid "Legend" msgid "Legend"
msgstr "Légende" msgstr "Légende"
@ -5328,12 +5345,20 @@ msgstr "photo"
msgid "SAS" msgid "SAS"
msgstr "SAS" msgstr "SAS"
#: sas/templates/sas/album.jinja:102
msgid "This album does not contain any photos."
msgstr "Cet album ne contient aucune photo."
#: sas/templates/sas/album.jinja:53 sas/templates/sas/album.jinja:55 #: sas/templates/sas/album.jinja:53 sas/templates/sas/album.jinja:55
#: sas/templates/sas/main.jinja:13 sas/templates/sas/main.jinja:15 #: sas/templates/sas/main.jinja:13 sas/templates/sas/main.jinja:15
#: sas/templates/sas/main.jinja:17 #: sas/templates/sas/main.jinja:17
msgid "preview" msgid "preview"
msgstr "miniature" msgstr "miniature"
#: sas/templates/sas/main.jinja:42
msgid "You must be logged in to see the SAS."
msgstr "Vous devez être connecté pour voir les photos."
#: sas/templates/sas/album.jinja:89 #: sas/templates/sas/album.jinja:89
msgid "Upload" msgid "Upload"
msgstr "Envoyer" msgstr "Envoyer"
@ -5752,6 +5777,12 @@ msgstr "Vous avez acheté %s"
msgid "You have a notification" msgid "You have a notification"
msgstr "Vous avez une notification" msgstr "Vous avez une notification"
#: core/templates/core/base.jinja
msgid "You do not have any unread notification"
msgstr "Vous n'avez aucune notification non lue"
#: sith/settings.py:624
#: sith/settings.py:648
#: sith/settings.py:650 #: sith/settings.py:650
msgid "Success!" msgid "Success!"
msgstr "Succès !" msgstr "Succès !"

View File

@ -69,7 +69,6 @@ class Picture(SithFile):
im = Image.open(BytesIO(f.read())) im = Image.open(BytesIO(f.read()))
(w, h) = im.size (w, h) = im.size
return (w / h) < 1 return (w / h) < 1
return False
def can_be_edited_by(self, user): def can_be_edited_by(self, user):
return user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) return user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID)
@ -79,11 +78,20 @@ class Picture(SithFile):
# Result is cached 4s for this user # Result is cached 4s for this user
if user.is_anonymous: if user.is_anonymous:
return False return False
perm = cache.get("%d_can_view_pictures" % (user.id), False) perm = cache.get("%d_can_view_pictures" % (user.id), False)
if perm:
# use cache only when user is in SAS Admins or when picture is moderated
if perm and (self.is_moderated or self.can_be_edited_by(user)):
return perm return perm
perm = self.is_in_sas and self.is_moderated and user.was_subscribed
perm = (
self.is_in_sas
and (self.is_moderated or self.can_be_edited_by(user))
and user.was_subscribed
)
cache.set("%d_can_view_pictures" % (user.id), perm, timeout=4) cache.set("%d_can_view_pictures" % (user.id), perm, timeout=4)
return perm return perm
def get_download_url(self): def get_download_url(self):

View File

@ -1,202 +1,248 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% from "core/macros.jinja" import paginate %} {% from "core/macros.jinja" import paginate %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('sas/album.scss') }}">
{%- endblock -%}
{% block title %} {% block title %}
{% trans %}SAS{% endtrans %} {% trans %}SAS{% endtrans %}
{% endblock %} {% endblock %}
{% macro print_path(file) %} {% macro print_path(file) %}
{% if file and file.parent %} {% if file and file.parent %}
{{ print_path(file.parent) }} {{ print_path(file.parent) }}
<a href="{{ url('sas:album', album_id=file.id) }}">{{ file.get_display_name() }}</a> > <a href="{{ url('sas:album', album_id=file.id) }}">{{ file.get_display_name() }}</a> /
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}
{% block content %} {% block content %}
<a href="{{ url('sas:main') }}">SAS</a> > {{ print_path(album.parent) }} {{ album.get_display_name() }} <code>
<h3>{{ album.get_display_name() }}</h3> <a href="{{ url('sas:main') }}">SAS</a> / {{ print_path(album.parent) }} {{ album.get_display_name() }}
<a href="{{ url('sas:album_edit', album_id=album.id) }}">{% trans %}Edit{% endtrans %}</a><br> </code>
{% set start = timezone.now() %}
<hr> {% set edit_mode = user.can_edit(album) %}
{% set edit_mode = user.can_edit(album) %} {% set start = timezone.now() %}
{% if edit_mode %}
<form action="" method="post" enctype="multipart/form-data" style="width: 100%;"> {% if edit_mode %}
{% csrf_token %} <form action="" method="post" enctype="multipart/form-data">
<p> {% csrf_token %}
<input name="delete" type="submit" value="{% trans %}Delete{% endtrans %}"> |
<input name="clear" type="submit" value="{% trans %}Clear clipboard{% endtrans %}"> | <div class="navbar">
<input name="cut" type="submit" value="{% trans %}Cut{% endtrans %}"> | <h3>{{ album.get_display_name() }}</h3>
<input name="paste" type="submit" value="{% trans %}Paste{% endtrans %}">
</p> <div class="toolbar">
{% if clipboard %} <a href="{{ url('sas:album_edit', album_id=album.id) }}">{% trans %}Edit{% endtrans %}</a>
<p>{% trans %}Clipboard: {% endtrans %} <input name="delete" type="submit" value="{% trans %}Delete{% endtrans %}">
<ul> <input name="cut" type="submit" value="{% trans %}Cut{% endtrans %}">
{% for f in clipboard %} <input {% if not clipboard %}disabled{% endif %} name="paste" type="submit" value="{% trans %}Paste{% endtrans %}">
<li>{{ f.get_full_path() }}</li> </div>
{% endfor %}
</ul>
</p>
{% endif %}
{% endif %}
<div>
{% for a in album.children_albums.order_by('-date') %}
<div style="display: inline-block;">
{% if edit_mode %}
<input type="checkbox" name="file_list" value="{{ a.id }}">
{% endif %}
{% if user.can_view(a) %}
<a href="{{ url("sas:album", album_id=a.id) }}" style="display: inline-block">
<div class="album{% if not a.is_moderated %} not_moderated{% endif %}">
<div>
{% if a.file %}
<img src="{{ a.get_download_url() }}" alt="{% trans %}preview{% endtrans %}">
{% else %}
<img src="{{ static('core/img/sas.jpg') }}" alt="{% trans %}preview{% endtrans %}">
{% endif %}
</div> </div>
{{ a.name }}
{% if clipboard %}
<div class="clipboard">
{% trans %}Clipboard: {% endtrans %}
<ul>
{% for f in clipboard %}
<li>{{ f.get_full_path() }}</li>
{% endfor %}
</ul>
<input name="clear" type="submit" value="{% trans %}Clear clipboard{% endtrans %}">
</div>
{% endif %}
{% endif %}
{% if album.children_albums.count() > 0 %}
<h4>{% trans %}Albums{% endtrans %}</h4>
<div class="albums">
{% for a in album.children_albums.order_by('-date') %}
{% if a.can_be_viewed_by(user) %}
<a href="{{ url('sas:album', album_id=a.id) }}">
<div
class="album{% if not a.is_moderated %} not_moderated{% endif %}"
style="background-image: url('{% if a.file %}{{ a.get_download_url() }}{% else %}{{ static('core/img/sas.jpg') }}{% endif %}');"
>
{% if not a.is_moderated %}
<div class="overlay">&nbsp;</div>
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
{% else %}
<div class="text">{{ a.name }}</div>
{% endif %}
</div>
{% if edit_mode %}
<input type="checkbox" name="file_list" value="{{ a.id }}">
{% endif %}
</a>
{% endif %}
{% endfor %}
</div> </div>
</a>
{% endif %} <br>
{% endif %}
<h4>{% trans %}Pictures{% endtrans %}</h4>
{% if pictures | length != 0 %}
<div class="photos">
{% for p in pictures %}
{% if p.can_be_viewed_by(user) %}
<a href="{{ url('sas:picture', picture_id=p.id) }}#pict">
<div
class="photo"
style="background-image: url('{{ p.get_download_thumb_url() }}')"
>
{% if not p.is_moderated %}
<div class="overlay">&nbsp;</div>
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
{% else %}
<div class="text">&nbsp;</div>
{% endif %}
</div>
{% if edit_mode %}
<input type="checkbox" name="file_list" value="{{ p.id }}">
{% endif %}
</a>
{% endif %}
{% endfor %}
</div> </div>
{% endfor %} {% else %}
</div> {% trans %}This album does not contain any photos.{% endtrans %}
<div> {% endif %}
{% for p in pictures %}
<div style="display: inline-block;"> {% if pictures.has_previous() or pictures.has_next() %}
{% if edit_mode %} <div class="paginator">
<input type="checkbox" name="file_list" value="{{ p.id }}"> {{ paginate(pictures, paginator) }}
{% endif %}
{% if user.can_view(p) %}
<div class="picture{% if not p.is_moderated %} not_moderated{% endif %}">
<a href="{{ url("sas:picture", picture_id=p.id) }}#pict">
<img src="{{ p.get_download_thumb_url() }}" alt="{{ p.get_display_name() }}" />
</a>
</div> </div>
{% endif %} {% endif %}
</div>
{% endfor %} {% if edit_mode %}
</div> </form>
<br> {% endif %}
{{ paginate(pictures, paginator) }}
{% if edit_mode %} {% if user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %}
</form> <form class="add-files" id="upload_form" action="" method="post" enctype="multipart/form-data">
{% endif %} {% csrf_token %}
<form id="upload_form" action="" method="post" enctype="multipart/form-data"> <div class="inputs">
{% csrf_token %} {{ form.as_p() }}
{{ form.as_p() }}
<p><input type="submit" value="{% trans %}Upload{% endtrans %}" /></p> <input type="submit" value="{% trans %}Upload{% endtrans %}" />
</form> </div>
<p style="font-size: small; color: #444;">{% trans %}Template generation time: {% endtrans %} </form>
{{ timezone.now() - start }} {% endif %}
</p>
<hr>
<p style="font-size: small; color: #444;">{% trans %}Template generation time: {% endtrans %}
{{ timezone.now() - start }}
</p>
{% endblock %} {% endblock %}
{% block script %} {% block script %}
{{ super() }} {{ super() }}
<script> <script>
$("form#upload_form").submit(function (event) { $("form#upload_form").submit(function (event) {
var formData = new FormData($(this)[0]); let formData = new FormData($(this)[0]);
if(!formData.get('album_name') && !formData.get('images').name) if(!formData.get('album_name') && !formData.get('images').name)
return false; return false;
if(!formData.get('images').name) { if(!formData.get('images').name) {
return true; return true;
}
event.preventDefault();
var errorlist;
if((errorlist = this.querySelector('#upload_form ul.errorlist.nonfield')) === null) {
errorlist = document.createElement('ul');
errorlist.classList.add('errorlist', 'nonfield');
this.insertBefore(errorlist, this.firstElementChild);
}
while(errorlist.childElementCount > 0)
errorlist.removeChild(errorlist.firstElementChild);
var progress;
if((progress = this.querySelector('progress')) === null) {
progress = document.createElement('progress');
progress.value = 0;
var p = document.createElement('p');
p.appendChild(progress);
this.insertBefore(p, this.lastElementChild);
}
var dataHolder;
if(formData.get('album_name')) {
dataHolder = new FormData();
dataHolder.set('csrfmiddlewaretoken', '{{ csrf_token }}');
dataHolder.set('album_name', formData.get('album_name'));
$.ajax({
method: 'POST',
url: "{{ url('sas:album_upload', album_id=object.id) }}",
data: dataHolder,
processData: false,
contentType: false,
success: onSuccess
});
}
var images = formData.getAll('images');
var imagesCount = images.length;
var completeCount = 0;
var poolSize = 1;
var imagePool = [];
while(images.length > 0 && imagePool.length < poolSize) {
var image = images.shift();
imagePool.push(image);
sendImage(image);
}
function sendImage(image) {
dataHolder = new FormData();
dataHolder.set('csrfmiddlewaretoken', '{{ csrf_token }}');
dataHolder.set('images', image);
$.ajax({
method: 'POST',
url: "{{ url('sas:album_upload', album_id=object.id) }}",
data: dataHolder,
processData: false,
contentType: false,
})
.fail(onSuccess.bind(undefined, image))
.done(onSuccess.bind(undefined, image))
.always(next.bind(undefined, image));
}
function next(image, status, jqXHR) {
var index;
if(index = imagePool.indexOf(image) !== -1) {
imagePool.splice(index, 1);
} }
var nextImage;
if(nextImage = images.shift()) {
imagePool.push(nextImage);
sendImage(nextImage); event.preventDefault();
let errorList;
if((errorList = this.querySelector('#upload_form ul.errorlist.nonfield')) === null) {
errorList = document.createElement('ul');
errorList.classList.add('errorlist', 'nonfield');
this.insertBefore(errorList, this.firstElementChild);
} }
}
function onSuccess(image, data, status, jqXHR) { while(errorList.childElementCount > 0)
if ($(data.responseText).find('.errorlist.nonfield')[0]) errorList.removeChild(errorList.firstElementChild);
var errors = Array.from($(data.responseText).find('.errorlist.nonfield')[0].children);
else let progress;
var errors = [] if((progress = this.querySelector('progress')) === null) {
while(errors.length > 0) progress = document.createElement('progress');
errorlist.appendChild(errors.shift()); progress.value = 0;
progress.value = ++completeCount / imagesCount; let p = document.createElement('p');
if(progress.value === 1 && errorlist.children.length === 0) p.appendChild(progress);
document.location.reload(true) this.insertBefore(p, this.lastElementChild);
} }
});
</script> let dataHolder;
if(formData.get('album_name')) {
dataHolder = new FormData();
dataHolder.set('csrfmiddlewaretoken', '{{ csrf_token }}');
dataHolder.set('album_name', formData.get('album_name'));
$.ajax({
method: 'POST',
url: "{{ url('sas:album_upload', album_id=object.id) }}",
data: dataHolder,
processData: false,
contentType: false,
success: onSuccess
});
}
let images = formData.getAll('images');
let imagesCount = images.length;
let completeCount = 0;
let poolSize = 1;
let imagePool = [];
while(images.length > 0 && imagePool.length < poolSize) {
let image = images.shift();
imagePool.push(image);
sendImage(image);
}
function sendImage(image) {
dataHolder = new FormData();
dataHolder.set('csrfmiddlewaretoken', '{{ csrf_token }}');
dataHolder.set('images', image);
$.ajax({
method: 'POST',
url: "{{ url('sas:album_upload', album_id=object.id) }}",
data: dataHolder,
processData: false,
contentType: false,
})
.fail(onSuccess.bind(undefined, image))
.done(onSuccess.bind(undefined, image))
.always(next.bind(undefined, image));
}
function next(image, _, __) {
let index = imagePool.indexOf(image);
let nextImage = images.shift();
if(index !== -1)
imagePool.splice(index, 1);
if(nextImage) {
imagePool.push(nextImage);
sendImage(nextImage);
}
}
function onSuccess(image, data, _, __) {
let errors = [];
if ($(data.responseText).find('.errorlist.nonfield')[0])
errors = Array.from($(data.responseText).find('.errorlist.nonfield')[0].children);
while(errors.length > 0)
errorList.appendChild(errors.shift());
progress.value = ++completeCount / imagesCount;
if(progress.value === 1 && errorList.children.length === 0)
document.location.reload()
}
});
</script>
{% endblock %} {% endblock %}

View File

@ -1,56 +1,110 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('sas/album.scss') }}">
{%- endblock -%}
{% block title %} {% block title %}
{% trans %}SAS{% endtrans %} {% trans %}SAS{% endtrans %}
{% endblock %} {% endblock %}
{% macro display_album(a) %} {% set edit_mode = user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %}
{% if a.is_moderated %}
<a href="{{ url("sas:album", album_id=a.id) }}"> {% macro display_album(a, checkbox) %}
<div class="album"> <a href="{{ url('sas:album', album_id=a.id) }}">
<div> {% if a.file %}
{% if a.file %} {% set img = a.get_download_url() %}
<img src="{{ a.get_download_url() }}" alt="{% trans %}preview{% endtrans %}"> {% elif a.children.filter(is_folder=False, is_moderated=True).exists() %}
{% elif a.children.filter(is_folder=False, is_moderated=True).exists() %} {% set img = a.children.filter(is_folder=False).first().as_picture.get_download_thumb_url() %}
<img src="{{ a.children.filter(is_folder=False).first().as_picture.get_download_thumb_url() }}" alt="{% trans %}preview{% endtrans %}"> {% else %}
{% else %} {% set img = static('core/img/sas.jpg') %}
<img src="{{ static('core/img/sas.jpg') }}" alt="{% trans %}preview{% endtrans %}"> {% endif %}
{% endif %}
</div> <div
{{ a.name }} class="album"
</div> style="background-image: url('{{ img }}');"
</a> >
{% elif user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %} <div class="text">
<div style="display: inline-block; border: solid 1px red; text-align: center"> {{ a.name }}
<p><a href="{{ url('core:file_moderate', file_id=a.id) }}?next={{ url('sas:moderation') }}">Moderate</a> or <a href="">Delete</a></p> </div>
<a href="{{ url("sas:album", album_id=a.id) }}">{{ a.name }}</a> </div>
</div> {# {% if edit_mode and checkbox %}
{% endif %} <input type="checkbox" name="file_list" value="{{ a.id }}">
{% endif %} #}
</a>
{% endmacro %} {% endmacro %}
{% block content %} {% block content %}
<h3>{% trans %}SAS{% endtrans %}</h3> <main>
<hr> <h3>{% trans %}SAS{% endtrans %}</h3>
<h4>{% trans %}Latest albums{% endtrans %}</h4>
<div> {% if not user.is_authenticated %}
{% for a in latest %} <p>{% trans %}You must be logged in to see the SAS.{% endtrans %}</p>
{{ display_album(a) }} {% else %}
{% endfor %} <br>
</div> <h4>{% trans %}Latest albums{% endtrans %}</h4>
<hr>
<h4>{% trans %}All categories{% endtrans %}</h4> <div class="albums">
<div> {% for a in latest %}
{% for a in categories %} {{ display_album(a) }}
{{ display_album(a) }} {% endfor %}
{% endfor %} </div>
</div>
{% if user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %} <br>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %} {% if edit_mode %}
{{ form.non_field_errors() }} <form action="" method="post" enctype="multipart/form-data">
<p>{{ form.album_name.errors }}<label for="{{ form.album_name.name }}">{{ form.album_name.label }}</label> {% csrf_token %}
{{ form.album_name }}</p>
<p><input type="submit" value="{% trans %}Create{% endtrans %}" /></p> <div class="navbar">
</form> <h4>{% trans %}All categories{% endtrans %}</h4>
{% endif %}
{# <div class="toolbar">
<input name="delete" type="submit" value="{% trans %}Delete{% endtrans %}">
</div> #}
</div>
{% if clipboard %}
<div class="clipboard">
{% trans %}Clipboard: {% endtrans %}
<ul>
{% for f in clipboard %}
<li>{{ f.get_full_path() }}</li>
{% endfor %}
</ul>
<input name="clear" type="submit" value="{% trans %}Clear clipboard{% endtrans %}">
</div>
{% endif %}
{% else %}
<h4>{% trans %}All categories{% endtrans %}</h4>
{% endif %}
<div class="albums">
{% for a in categories %}
{{ display_album(a, true) }}
{% endfor %}
</div>
{% if edit_mode %}
</form>
<br>
<form class="add-files" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="inputs">
<div>
<label for="{{ form.album_name.name }}">{{ form.album_name.label }}</label>
{{ form.album_name }}
</div>
<input type="submit" value="{% trans %}Create{% endtrans %}" />
</div>
{{ form.non_field_errors() }}
{{ form.album_name.errors }}
</form>
{% endif %}
{% endif %}
</main>
{% endblock %} {% endblock %}

View File

@ -1,150 +1,176 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block head %} {%- block additional_css -%}
{{ super() }} <link rel="stylesheet" href="{{ scss('sas/picture.scss') }}">
<style> {%- endblock -%}
#prev, #next {
display: inline-block;
width: 42%;
height: 100px;
margin: 0.5%;
border: solid 1px grey;
overflow: hidden;
background: #aaa;
text-align: center;
}
#prev img, #next img {
display: block;
margin: auto;
max-height: 80%;
max-width: 100%;
}
</style>
{% if picture.get_previous() %} {% block head %}
<link rel="preload" as="image" href="{{ url("sas:download_compressed", picture_id=picture.get_previous().id) }}"> {{ super() }}
{% endif %}
{% if picture.get_next() %} {% if picture.get_previous() %}
<link rel="preload" as="image" href="{{ url("sas:download_compressed", picture_id=picture.get_next().id) }}"> <link rel="preload" as="image" href="{{ url("sas:download_compressed", picture_id=picture.get_previous().id) }}">
{% endif %} {% endif %}
{% if picture.get_next() %}
<link rel="preload" as="image" href="{{ url("sas:download_compressed", picture_id=picture.get_next().id) }}">
{% endif %}
{% endblock %} {% endblock %}
{% block title %} {% block title %}
{% trans %}SAS{% endtrans %} {% trans %}SAS{% endtrans %}
{% endblock %} {% endblock %}
{% macro print_path(file) %} {% macro print_path(file) %}
{% if file and file.parent %} {% if file and file.parent %}
{{ print_path(file.parent) }} {{ print_path(file.parent) }}
<a href="{{ url('sas:album', album_id=file.id) }}">{{ file.get_display_name() }}</a> > <a href="{{ url('sas:album', album_id=file.id) }}">{{ file.get_display_name() }}</a> /
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}
{% block content %} {% block content %}
<a href="{{ url('sas:main') }}">SAS</a> > {{ print_path(picture.parent) }} {{ picture.get_display_name() }} <code>
({{ picture.parent.children.filter(id__lte=picture.id).count() }} / {{ picture.parent.children.count() }}) <a href="{{ url('sas:main') }}">SAS</a> / {{ print_path(picture.parent) }} {{ picture.get_display_name() }}
<h3> {{ picture.get_display_name() }}</h3> </code>
<div style="display: inline-block; width: 19%; vertical-align: top; overflow: hidden; float: right">
<div> <br>
<div id="prev">
{% if picture.get_previous() %} <div class="title">
<a href="{{ url("sas:picture", picture_id=picture.get_previous().id) }}#pict"> <h3>{{ picture.get_display_name() }}</h3>
&larr; <h4>{{ picture.parent.children.filter(id__lte=picture.id).count() }} / {{ picture.parent.children.count() }}</h4>
<img src="{{ picture.get_previous().as_picture.get_download_thumb_url() }}" alt="{{ picture.get_previous().get_display_name() }}" />
</a>
{% endif %}
</div>
<div id="next">
{% if picture.get_next() %}
<a href="{{ url("sas:picture", picture_id=picture.get_next().id) }}#pict">
&rarr;
<img src="{{ picture.get_next().as_picture.get_download_thumb_url() }}" alt="{{ picture.get_next().get_display_name() }}" />
</a>
{% endif %}
</div>
</div> </div>
<div>
<h5>{% trans %}People{% endtrans %}</h5>
<ul> {% if not picture.is_moderated %}
{% for r in picture.people.all() %} {% set next = picture.get_next() %}
<li> {% if not next %}
<a href="{{ r.user.get_absolute_url() }}">{{ r.user.get_short_name() }}</a> {% set next = url('sas:moderation') %}
{% if user == r.user or user.can_edit(picture) %} {% else %}
<a href="?remove_user={{ r.user.id }}">{% trans %}Delete{% endtrans %}</a> {% set next = next.get_absolute_url() + "#pict" %}
{% endif %}
<div class="moderation">
<div>
{% if picture.asked_for_removal %}
<span class="important">{% trans %}Asked for removal{% endtrans %}</span>
{% else %}
&nbsp;
{% endif %} {% endif %}
</li> </div>
{% endfor %} <div>
</ul> <a href="{{ url('core:file_moderate', file_id=picture.id) }}?next={{ next }}">
<form action="" method="post" enctype="multipart/form-data" style="margin: 0px;"> {% trans %}Moderate{% endtrans %}
{% csrf_token %} </a>
{{ form.as_p() }} <a href="{{ url('core:file_delete', file_id=picture.id) }}?next={{ next }}">
<p><input type="submit" value="{% trans %}Go{% endtrans %}" /></p> {% trans %}Delete{% endtrans %}
</form> </a>
</div> </div>
<div> </div>
<h5>{% trans %}Infos{% endtrans %}</h5>
<p>{% trans %}Date: {% endtrans %}{{ picture.date|date(DATETIME_FORMAT) }}</p>
<p>{% trans %}Owner: {% endtrans %}<a href="{{ picture.owner.get_absolute_url() }}">{{ picture.owner.get_short_name() }}</a></p>
{% if picture.moderator %}
<p>{% trans %}Moderator: {% endtrans %}<a href="{{ picture.moderator.get_absolute_url() }}">{{ picture.moderator.get_short_name() }}</a></p>
{% endif %}
<p>{{ picture.parent.children.filter(id__lte=picture.id).count() }} / {{ picture.parent.children.count() }}</p>
</div>
<div>
<h5>{% trans %}Tools{% endtrans %}</h5>
<p>
<a href="{{ picture.get_download_url() }}">{% trans %}HD version{% endtrans %}</a>
</p>
<p style="font-size: smaller;">
<a href="{{ url('sas:picture_edit', picture_id=picture.id) }}">{% trans %}Edit{% endtrans %}</a><br>
<a href="?rotate_left">{% trans %}Rotate left{% endtrans %}</a><br>
<a href="?rotate_right">{% trans %}Rotate right{% endtrans %}</a><br>
<a href="?ask_removal">{% trans %}Ask for removal{% endtrans %}</a><br>
</p>
</div>
</div>
{% if picture.is_moderated %}
<div id="pict">
{% else %}
<div id="pict" style="border: solid #f00 2px; box-shadow: red 0px 0px 5px">
{% set next = picture.get_next() %}
{% if not next %}
{% set next = url('sas:moderation') %}
{% else %}
{% set next = next.get_absolute_url() + "#pict" %}
{% endif %}
<div style="background: lightgrey; padding: 2px;">
{% if picture.asked_for_removal %}
<span class="important">{% trans %}Asked for removal{% endtrans %}</span>
{% endif %} {% endif %}
<a href="{{ url('core:file_moderate', file_id=picture.id) }}?next={{ next }}">
{% trans %}Moderate{% endtrans %}</a> | <div class="container">
<a href="{{ url('core:file_delete', file_id=picture.id) }}?next={{ next }}"> <div class="main">
{% trans %}Delete{% endtrans %}</a>
</div> <div class="photo">
{% endif %} <img src="{{ picture.get_download_compressed_url() }}" alt="{{ picture.get_display_name() }}"/>
{% if picture.is_vertical %} </div>
<img src="{{ picture.get_download_compressed_url() }}" alt="{{ picture.get_display_name() }}" style="width: 60%; display: block; margin: auto"/>
{% else %} <div class="general">
<img src="{{ picture.get_download_compressed_url() }}" alt="{{ picture.get_display_name() }}" style="width: 100%; display: block; margin: auto"/> <div class="infos">
{% endif %} <h5>{% trans %}Infos{% endtrans %}</h5>
</div> <div>
<div>
<span>{% trans %}Date: {% endtrans %}</span>
<span>{{ picture.date|date(DATETIME_FORMAT) }}</span>
</div>
<div>
<span>{% trans %}Owner: {% endtrans %}</span>
<a href="{{ picture.owner.get_absolute_url() }}">{{ picture.owner.get_short_name() }}</a>
</div>
{% if picture.moderator %}
<div>
<span>{% trans %}Moderator: {% endtrans %}</span>
<a href="{{ picture.moderator.get_absolute_url() }}">{{ picture.moderator.get_short_name() }}</a>
</div>
{% endif %}
</div>
</div>
<div class="tools">
<h5>{% trans %}Tools{% endtrans %}</h5>
<div>
<div>
<a class="text" href="{{ picture.get_download_url() }}">{% trans %}HD version{% endtrans %}</a>
<br>
<a class="text danger" href="?ask_removal">{% trans %}Ask for removal{% endtrans %}</a>
</div>
<div class="buttons">
<a class="button" href="{{ url('sas:picture_edit', picture_id=picture.id) }}">✏️</a>
<a class="button" href="?rotate_left">↺</a>
<a class="button" href="?rotate_right">↻</a>
</div>
</div>
</div>
</div>
</div>
<div class="subsection">
<div class="navigation">
<div id="prev">
{% if picture.get_previous() %}
<a href="{{ url( 'sas:picture', picture_id=picture.get_previous().id) }}#pict">
<div style="background-image: url('{{ picture.get_previous().as_picture.get_download_thumb_url() }}');"></div>
</a>
{% endif %}
</div>
<div id="next">
{% if picture.get_next() %}
<a href="{{ url( 'sas:picture', picture_id=picture.get_next().id) }}#pict">
<div style="background-image: url('{{ picture.get_next().as_picture.get_download_thumb_url() }}');"></div>
</a>
{% endif %}
</div>
</div>
<div class="tags">
<h5>{% trans %}People{% endtrans %}</h5>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p() }}
<input type="submit" value="{% trans %}Go{% endtrans %}" />
</form>
<ul>
{% for r in picture.people.all() %}
<li>
<a class="user" href="{{ r.user.get_absolute_url() }}">
{% if r.user.profile_pict %}
<img src="{{ r.user.profile_pict.get_download_url() }}">
{% endif %}
<span>{{ r.user.get_short_name() }}</span>
</a>
{% if user == r.user or user.can_edit(picture) %}
<a class="delete" href="?remove_user={{ r.user.id }}">❌</a>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endblock %} {% endblock %}
{% block script %} {% block script %}
{{ super() }} {{ super() }}
<script> <script>
$( function() { $(() => {
$(document).keydown(function (e) { $(document).keydown((e) => {
if (e.keyCode == 37) { switch (e.keyCode) {
console.log("prev"); case 37:
$('#prev a')[0].click(); $('#prev a')[0].click();
} else if (e.keyCode == 39) { case 39:
console.log("next"); $('#next a')[0].click();
$('#next a')[0].click(); }
} });
}); });
} ); </script>
</script>
{% endblock %} {% endblock %}

View File

@ -357,7 +357,7 @@ SITH_FORUM_PAGE_LENGTH = 30
# SAS variables # SAS variables
SITH_SAS_ROOT_DIR_ID = 4 SITH_SAS_ROOT_DIR_ID = 4
SITH_SAS_IMAGES_PER_PAGE = 30 SITH_SAS_IMAGES_PER_PAGE = 60
SITH_BOARD_SUFFIX = "-bureau" SITH_BOARD_SUFFIX = "-bureau"
SITH_MEMBER_SUFFIX = "-membres" SITH_MEMBER_SUFFIX = "-membres"