mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-12 21:09:24 +00:00
Compare commits
9 Commits
feature/im
...
features/m
Author | SHA1 | Date | |
---|---|---|---|
f234f94171 | |||
fa758867cc | |||
f41ff281fb | |||
321cb72ca8 | |||
c436d39014 | |||
b9298792ae | |||
4f9d5ae7b1 | |||
259337dff1 | |||
288764b551 |
4
.github/actions/setup_project/action.yml
vendored
4
.github/actions/setup_project/action.yml
vendored
@ -6,13 +6,13 @@ runs:
|
||||
- name: Install apt packages
|
||||
uses: awalsh128/cache-apt-pkgs-action@latest
|
||||
with:
|
||||
packages: gettext libxapian-dev libgraphviz-dev
|
||||
packages: gettext libgraphviz-dev
|
||||
version: 1.0 # increment to reset cache
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install gettext libxapian-dev libgraphviz-dev
|
||||
sudo apt install gettext libgraphviz-dev
|
||||
shell: bash
|
||||
|
||||
- name: Set up python
|
||||
|
10
.github/actions/setup_xapian/action.yml
vendored
10
.github/actions/setup_xapian/action.yml
vendored
@ -1,10 +0,0 @@
|
||||
name: "Setup xapian"
|
||||
description: "Setup the xapian indexes"
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup xapian index
|
||||
run: |
|
||||
mkdir -p /dev/shm/search_indexes
|
||||
ln -s /dev/shm/search_indexes sith/search_indexes
|
||||
shell: bash
|
16
.github/workflows/ci.yml
vendored
16
.github/workflows/ci.yml
vendored
@ -2,13 +2,10 @@ name: Sith 3 CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- taiste
|
||||
branches: [master, taiste, features/**]
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- taiste
|
||||
branches: [master, taiste]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
black:
|
||||
@ -24,11 +21,16 @@ jobs:
|
||||
tests:
|
||||
name: Run tests and generate coverage report
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.14
|
||||
env:
|
||||
discovery.type: single-node
|
||||
ports:
|
||||
- 9200
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup_project
|
||||
- uses: ./.github/actions/setup_xapian
|
||||
- uses: ./.github/actions/compile_messages
|
||||
- name: Run tests
|
||||
run: poetry run coverage run ./manage.py test
|
||||
|
3
.github/workflows/taiste.yml
vendored
3
.github/workflows/taiste.yml
vendored
@ -2,7 +2,8 @@ name: Sith3 taiste
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ taiste ]
|
||||
branches: [taiste]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deployment:
|
||||
|
@ -2,7 +2,7 @@
|
||||
{% from 'core/macros.jinja' import user_profile_link, paginate %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans %}Sellings{% endtrans %}</h3>
|
||||
<h3>{% trans %}Sales{% endtrans %}</h3>
|
||||
<form id="form" action="?page=1" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
|
@ -30,7 +30,7 @@
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% if object.club_account.exists() %}
|
||||
<h4>{% trans %}Accouting: {% endtrans %}</h4>
|
||||
<h4>{% trans %}Accounting: {% endtrans %}</h4>
|
||||
<ul>
|
||||
{% for ca in object.club_account.all() %}
|
||||
<li><a href="{{ url('accounting:club_details', c_account_id=ca.id) }}">{{ ca.get_display_name() }}</a></li>
|
||||
|
@ -39,7 +39,7 @@
|
||||
<p> <a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% if user.can_edit(news) %}
|
||||
<p> <a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit (will be remoderated){% endtrans %}</a></p>
|
||||
<p> <a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit (will be moderated again){% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
27
com/tests.py
27
com/tests.py
@ -159,6 +159,33 @@ class NewsTest(TestCase):
|
||||
self.assertFalse(self.new.is_owned_by(self.anonymous))
|
||||
self.assertFalse(self.new.is_owned_by(self.sli))
|
||||
|
||||
def test_news_viewer(self):
|
||||
"""
|
||||
Test that moderated news can be viewed by anyone
|
||||
and not moderated news only by com admins
|
||||
"""
|
||||
# by default a news isn't moderated
|
||||
self.assertTrue(self.new.can_be_viewed_by(self.com_admin))
|
||||
self.assertFalse(self.new.can_be_viewed_by(self.sli))
|
||||
self.assertFalse(self.new.can_be_viewed_by(self.anonymous))
|
||||
self.assertFalse(self.new.can_be_viewed_by(self.author))
|
||||
|
||||
self.new.is_moderated = True
|
||||
self.new.save()
|
||||
self.assertTrue(self.new.can_be_viewed_by(self.com_admin))
|
||||
self.assertTrue(self.new.can_be_viewed_by(self.sli))
|
||||
self.assertTrue(self.new.can_be_viewed_by(self.anonymous))
|
||||
self.assertTrue(self.new.can_be_viewed_by(self.author))
|
||||
|
||||
def test_news_editor(self):
|
||||
"""
|
||||
Test that only com admins can edit news
|
||||
"""
|
||||
self.assertTrue(self.new.can_be_edited_by(self.com_admin))
|
||||
self.assertFalse(self.new.can_be_edited_by(self.sli))
|
||||
self.assertFalse(self.new.can_be_edited_by(self.anonymous))
|
||||
self.assertFalse(self.new.can_be_edited_by(self.author))
|
||||
|
||||
|
||||
class WeekmailArticleTest(TestCase):
|
||||
@classmethod
|
||||
|
@ -180,14 +180,15 @@ def get_group(*, pk: int = None, name: str = None) -> Optional[Group]:
|
||||
:param pk: The primary key of the group
|
||||
:param name: The name of the group
|
||||
:return: The group if it exists, else None
|
||||
:raises ValueError: If no group matches the criteria
|
||||
:raise ValueError: If no group matches the criteria
|
||||
"""
|
||||
if pk is None and name is None:
|
||||
raise ValueError("Either pk or name must be set")
|
||||
if name is not None:
|
||||
name = name.replace(" ", "_") # avoid errors with memcached backend
|
||||
pk_or_name: Union[str, int] = pk if pk is not None else name
|
||||
|
||||
# replace space characters to hide warnings with memcached backend
|
||||
pk_or_name: Union[str, int] = pk if pk is not None else name.replace(" ", "_")
|
||||
group = cache.get(f"sith_group_{pk_or_name}")
|
||||
|
||||
if group == "not_found":
|
||||
# Using None as a cache value is a little bit tricky,
|
||||
# so we use a special string to represent None
|
||||
@ -809,6 +810,10 @@ class AnonymousUser(AuthAnonymousUser):
|
||||
def can_edit(self, obj):
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_com_admin(self):
|
||||
return False
|
||||
|
||||
def can_view(self, obj):
|
||||
if (
|
||||
hasattr(obj, "view_groups")
|
||||
|
4
core/static/core/font-awesome/css/font-awesome.min.css
vendored
Normal file
4
core/static/core/font-awesome/css/font-awesome.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
core/static/core/font-awesome/fonts/FontAwesome.otf
Normal file
BIN
core/static/core/font-awesome/fonts/FontAwesome.otf
Normal file
Binary file not shown.
BIN
core/static/core/font-awesome/fonts/fontawesome-webfont.eot
Normal file
BIN
core/static/core/font-awesome/fonts/fontawesome-webfont.eot
Normal file
Binary file not shown.
2671
core/static/core/font-awesome/fonts/fontawesome-webfont.svg
Normal file
2671
core/static/core/font-awesome/fonts/fontawesome-webfont.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 434 KiB |
BIN
core/static/core/font-awesome/fonts/fontawesome-webfont.ttf
Normal file
BIN
core/static/core/font-awesome/fonts/fontawesome-webfont.ttf
Normal file
Binary file not shown.
BIN
core/static/core/font-awesome/fonts/fontawesome-webfont.woff
Normal file
BIN
core/static/core/font-awesome/fonts/fontawesome-webfont.woff
Normal file
Binary file not shown.
BIN
core/static/core/font-awesome/fonts/fontawesome-webfont.woff2
Normal file
BIN
core/static/core/font-awesome/fonts/fontawesome-webfont.woff2
Normal file
Binary file not shown.
1232
core/static/core/font-awesome/js/fontawesome.min.js
vendored
Normal file
1232
core/static/core/font-awesome/js/fontawesome.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,165 +0,0 @@
|
||||
Fonticons, Inc. (https://fontawesome.com)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Font Awesome Free License
|
||||
|
||||
Font Awesome Free is free, open source, and GPL friendly. You can use it for
|
||||
commercial projects, open source projects, or really almost whatever you want.
|
||||
Full Font Awesome Free license: https://fontawesome.com/license/free.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
|
||||
|
||||
The Font Awesome Free download is licensed under a Creative Commons
|
||||
Attribution 4.0 International License and applies to all icons packaged
|
||||
as SVG and JS file types.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Fonts: SIL OFL 1.1 License
|
||||
|
||||
In the Font Awesome Free download, the SIL OFL license applies to all icons
|
||||
packaged as web and desktop font files.
|
||||
|
||||
Copyright (c) 2023 Fonticons, Inc. (https://fontawesome.com)
|
||||
with Reserved Font Name: "Font Awesome".
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
SIL OPEN FONT LICENSE
|
||||
Version 1.1 - 26 February 2007
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting — in part or in whole — any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Code: MIT License (https://opensource.org/licenses/MIT)
|
||||
|
||||
In the Font Awesome Free download, the MIT license applies to all non-font and
|
||||
non-icon files.
|
||||
|
||||
Copyright 2023 Fonticons, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Attribution
|
||||
|
||||
Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
|
||||
Awesome Free files already contain embedded comments with sufficient
|
||||
attribution, so you shouldn't need to do anything additional when using these
|
||||
files normally.
|
||||
|
||||
We've kept attribution comments terse, so we ask that you do not actively work
|
||||
to remove them from files, especially code. They're a great way for folks to
|
||||
learn about Font Awesome.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Brand Icons
|
||||
|
||||
All brand icons are trademarks of their respective owners. The use of these
|
||||
trademarks does not indicate endorsement of the trademark holder by Font
|
||||
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
|
||||
to represent the company, product, or service to which they refer.**
|
9
core/static/core/fontawesome/css/all.min.css
vendored
9
core/static/core/fontawesome/css/all.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,6 +0,0 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}
|
@ -1,6 +0,0 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}
|
File diff suppressed because one or more lines are too long
@ -1,6 +0,0 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}
|
File diff suppressed because one or more lines are too long
@ -1,6 +0,0 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}
|
6
core/static/core/fontawesome/js/all.min.js
vendored
6
core/static/core/fontawesome/js/all.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6
core/static/core/fontawesome/js/solid.min.js
vendored
6
core/static/core/fontawesome/js/solid.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -191,42 +191,96 @@ $hovered-red-text-color: #ff4d4d;
|
||||
>.right {
|
||||
flex: 1;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
|
||||
>.links {
|
||||
>.user {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
width: 100%;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
> a {
|
||||
display: block;
|
||||
min-width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-position: center center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-color: $background-color;
|
||||
}
|
||||
|
||||
>.options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
|
||||
>.username {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
gap: 10px;
|
||||
gap: 5px;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
>a {
|
||||
color: $text-color;
|
||||
|
||||
&:hover {
|
||||
color: $hovered-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>.links {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 15px;
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
@media (max-width: 375px) {
|
||||
height: 30px;
|
||||
>a {
|
||||
text-align: right;
|
||||
color: $text-color;
|
||||
|
||||
&:hover {
|
||||
color: $hovered-text-color;
|
||||
}
|
||||
|
||||
> * {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 20px;
|
||||
&:last-child {
|
||||
color: $red-text-color;
|
||||
|
||||
> * {
|
||||
font-size: 20px;
|
||||
&:hover {
|
||||
color: $hovered-red-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>.notification {
|
||||
height: 100%;
|
||||
width: 55px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
>a {
|
||||
color: $text-color;
|
||||
position: relative;
|
||||
font-size: 25px;
|
||||
|
||||
&:hover {
|
||||
color: $hovered-text-color;
|
||||
@ -317,69 +371,6 @@ $hovered-red-text-color: #ff4d4d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>a {
|
||||
text-align: right;
|
||||
color: $text-color;
|
||||
|
||||
&:hover {
|
||||
color: $hovered-text-color;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
color: $red-text-color;
|
||||
|
||||
&:hover {
|
||||
color: $hovered-red-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>.user {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
width: 100%;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
> a {
|
||||
display: block;
|
||||
min-width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-position: center center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-color: $background-color;
|
||||
}
|
||||
|
||||
>.username {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 5px;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
>a {
|
||||
color: $text-color;
|
||||
|
||||
&:hover {
|
||||
color: $hovered-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
>.left {
|
||||
|
@ -1031,7 +1031,7 @@ thead {
|
||||
}
|
||||
|
||||
tbody > tr {
|
||||
&:nth-child(even) {
|
||||
&:nth-child(even):not(.highlight) {
|
||||
background: $primary-neutral-light-color;
|
||||
}
|
||||
&.clickable:hover {
|
||||
|
@ -16,10 +16,9 @@
|
||||
{# Thile file is quite heavy (around 250kb), so declaring it in a block allows easy removal #}
|
||||
<link rel="stylesheet" href="{{ static('core/js/ui/jquery-ui.min.css') }}">
|
||||
{% endblock %}
|
||||
<!-- Font Awesome 6 -->
|
||||
<link rel="preload" as="style" href="{{ static('core/fontawesome/css/all.min.css') }}" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="{{ static('core/fontawesome/css/all.min.css') }}"></noscript>
|
||||
<script defer href="{{ static('core/fontawesome/js/all.min.js') }}"></script>
|
||||
<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>
|
||||
@ -73,11 +72,11 @@
|
||||
<a href="{{ url('counter:activity', counter_id=bar.id) }}">
|
||||
{% endif %}
|
||||
{% if bar.is_inactive() %}
|
||||
<i class="fa-solid fa-question" style="color: #f39c12"></i>
|
||||
<i class="fa fa-question" style="color: #f39c12"></i>
|
||||
{% elif bar.is_open(): %}
|
||||
<i class="fa-solid fa-check" style="color: #2ecc71"></i>
|
||||
<i class="fa fa-check" style="color: #2ecc71"></i>
|
||||
{% else %}
|
||||
<i class="fa-solid fa-xmark" style="color: #eb2f06"></i>
|
||||
<i class="fa fa-times" style="color: #eb2f06"></i>
|
||||
{% endif %}
|
||||
<span>{{ bar }}</span>
|
||||
</a>
|
||||
@ -88,9 +87,15 @@
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="user">
|
||||
<div class="options">
|
||||
<div class="username">
|
||||
<a href="{{ url('core:user_profile', user_id=user.id) }}">{{ user.get_display_name() }}</a>
|
||||
</div>
|
||||
<div class="links">
|
||||
<a href="{{ url('core:user_tools') }}">{% trans %}Tools{% endtrans %}</a>
|
||||
<a href="{{ url('core:logout') }}">{% trans %}Logout{% endtrans %}</a>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href="{{ url('core:user_profile', user_id=user.id) }}"
|
||||
{% if user.profile_pict %}
|
||||
@ -100,16 +105,19 @@
|
||||
{% endif %}
|
||||
></a>
|
||||
</div>
|
||||
|
||||
<div class="links">
|
||||
<div class="notification">
|
||||
<a href="#" onclick="display_notif()">
|
||||
<i class="fa-solid fa-bell"></i>
|
||||
<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 %} {% endif %} </span>
|
||||
{% if notification_count < 100 %}
|
||||
{{ notification_count }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
<div id="header_notif">
|
||||
@ -117,7 +125,7 @@
|
||||
{% 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) }}">
|
||||
<a href="{{ url("core:notification", notif_id=n.id) }}">
|
||||
<div class="datetime">
|
||||
<span class="header_notif_date">
|
||||
{{ n.date|localtime|date(DATE_FORMAT) }}
|
||||
@ -146,9 +154,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="{{ url('core:user_tools') }}"><i class="fa-solid fa-wrench"></i></a>
|
||||
<a href="{{ url('core:logout') }}"><i class="fa-solid fa-right-from-bracket"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -190,7 +195,7 @@
|
||||
{% block nav %}
|
||||
{% if not popup %}
|
||||
<nav class="navbar">
|
||||
<button class="expand-button" onclick="showMenu()"><i class="fa-solid fa-bars"></i></button>
|
||||
<button class="expand-button" onclick="showMenu()"><i class="fa fa-bars"></i></button>
|
||||
<div id="navbar-content" class="content" style="display: none;">
|
||||
<a class="link" href="{{ url('core:index') }}">{% trans %}Main{% endtrans %}</a>
|
||||
<div class="menu">
|
||||
@ -198,11 +203,7 @@
|
||||
<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>
|
||||
<li><a href="{{ url('core:page', page_name='utbm-associations') }}">{% trans %}Others UTBM's Associations{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="menu">
|
||||
|
@ -4,9 +4,9 @@
|
||||
{% block file %}
|
||||
<h3>
|
||||
{% if file.is_folder %}
|
||||
<i class="fa-solid fa-folder-open"></i>
|
||||
<i class="fa fa-folder fa-3x" aria-hidden="true"></i>
|
||||
{% else %}
|
||||
<i class="fa-solid fa-file"></i>
|
||||
<i class="fa fa-file fa-3x" aria-hidden="true"></i>
|
||||
{% endif %}
|
||||
{{ file.get_display_name() }}
|
||||
</h3>
|
||||
@ -41,9 +41,9 @@
|
||||
<li style="list-style-type: none;">
|
||||
<input type="checkbox" name="file_list" value="{{ f.id }}">
|
||||
{% if f.is_folder %}
|
||||
<i class="fa-solid fa-folder"></i>
|
||||
<i class="fa fa-folder" aria-hidden="true"></i>
|
||||
{% else %}
|
||||
<i class="fa-solid fa-file"></i>
|
||||
<i class="fa fa-file" aria-hidden="true"></i>
|
||||
{% endif %}
|
||||
<a href="{{ url('core:file_detail', file_id=f.id, popup=popup) }}">{{ f.get_display_name() }}</a></li>
|
||||
{% endfor %}
|
||||
|
@ -8,9 +8,9 @@
|
||||
{% for f in file_list %}
|
||||
<li style="list-style-type: none;">
|
||||
{% if f.is_folder %}
|
||||
<i class="fa-solid fa-folder"></i>
|
||||
<i class="fa fa-folder" aria-hidden="true"></i>
|
||||
{% else %}
|
||||
<i class="fa-solid fa-file"></i>
|
||||
<i class="fa fa-file" aria-hidden="true"></i>
|
||||
{% endif %}
|
||||
<a href="{{ url('core:file_detail', file_id=f.id, popup=popup) }}">{{ f.name }}</a></li>
|
||||
{% endfor %}
|
||||
|
@ -40,11 +40,11 @@
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro fb_quick(news) -%}
|
||||
<a rel="nofollow" target="#" href="https://www.facebook.com/sharer/sharer.php?u={{ news.get_full_url() }}" class="fb fa-brands fa-facebook fa-2x"></a>
|
||||
<a rel="nofollow" target="#" href="https://www.facebook.com/sharer/sharer.php?u={{ news.get_full_url() }}" class="fb fa fa-facebook-square fa-2x"></a>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro tweet_quick(news) -%}
|
||||
<a rel="nofollow" target="#" href="https://twitter.com/intent/tweet?text={{ news.get_full_url() }}" class="twitter fa-brands fa-twitter fa-2x"></a>
|
||||
<a rel="nofollow" target="#" href="https://twitter.com/intent/tweet?text={{ news.get_full_url() }}" class="twitter fa fa-twitter-square fa-2x"></a>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro user_mini_profile(user) %}
|
||||
|
@ -40,25 +40,25 @@
|
||||
{
|
||||
name: "heading-smaller",
|
||||
action: EasyMDE.toggleHeadingSmaller,
|
||||
className: "fa-solid fa-heading",
|
||||
className: "fa fa-header",
|
||||
title: "{{ translations.heading_smaller }}"
|
||||
},
|
||||
{
|
||||
name: "italic",
|
||||
action: EasyMDE.toggleItalic,
|
||||
className: "fa-solid fa-italic",
|
||||
className: "fa fa-italic",
|
||||
title: "{{ translations.italic }}"
|
||||
},
|
||||
{
|
||||
name: "bold",
|
||||
action: EasyMDE.toggleBold,
|
||||
className: "fa-solid fa-bold",
|
||||
className: "fa fa-bold",
|
||||
title: "{{ translations.bold }}"
|
||||
},
|
||||
{
|
||||
name: "strikethrough",
|
||||
action: EasyMDE.toggleStrikethrough,
|
||||
className: "fa-solid fa-strikethrough",
|
||||
className: "fa fa-strikethrough",
|
||||
title: "{{ translations.strikethrough }}"
|
||||
},
|
||||
{
|
||||
@ -67,7 +67,7 @@
|
||||
let cm = editor.codemirror;
|
||||
cm.replaceSelection('__' + cm.getSelection() + '__');
|
||||
},
|
||||
className: "fa-solid fa-underline",
|
||||
className: "fa fa-underline",
|
||||
title: "{{ translations.underline }}"
|
||||
},
|
||||
{
|
||||
@ -76,7 +76,7 @@
|
||||
let cm = editor.codemirror;
|
||||
cm.replaceSelection('<sup>' + cm.getSelection() + '</sup>');
|
||||
},
|
||||
className: "fa-solid fa-superscript",
|
||||
className: "fa fa-superscript",
|
||||
title: "{{ translations.superscript }}"
|
||||
},
|
||||
{
|
||||
@ -85,84 +85,84 @@
|
||||
let cm = editor.codemirror;
|
||||
cm.replaceSelection('<sub>' + cm.getSelection() + '</sub>');
|
||||
},
|
||||
className: "fa-solid fa-subscript",
|
||||
className: "fa fa-subscript",
|
||||
title: "{{ translations.subscript }}"
|
||||
},
|
||||
{
|
||||
name: "code",
|
||||
action: EasyMDE.toggleCodeBlock,
|
||||
className: "fa-solid fa-code",
|
||||
className: "fa fa-code",
|
||||
title: "{{ translations.code }}"
|
||||
},
|
||||
"|",
|
||||
{
|
||||
name: "quote",
|
||||
action: EasyMDE.toggleBlockquote,
|
||||
className: "fa-solid fa-quote-left",
|
||||
className: "fa fa-quote-left",
|
||||
title: "{{ translations.quote }}"
|
||||
},
|
||||
{
|
||||
name: "unordered-list",
|
||||
action: EasyMDE.toggleUnorderedList,
|
||||
className: "fa-solid fa-list-ul",
|
||||
className: "fa fa-list-ul",
|
||||
title: "{{ translations.unordered_list }}"
|
||||
},
|
||||
{
|
||||
name: "ordered-list",
|
||||
action: EasyMDE.toggleOrderedList,
|
||||
className: "fa-solid fa-list-ol",
|
||||
className: "fa fa-list-ol",
|
||||
title: "{{ translations.ordered_list }}"
|
||||
},
|
||||
"|",
|
||||
{
|
||||
name: "link",
|
||||
action: EasyMDE.drawLink,
|
||||
className: "fa-solid fa-link",
|
||||
className: "fa fa-link",
|
||||
title: "{{ translations.link }}"
|
||||
},
|
||||
{
|
||||
name: "image",
|
||||
action: EasyMDE.drawImage,
|
||||
className: "fa-solid fa-image",
|
||||
className: "fa fa-picture-o",
|
||||
title: "{{ translations.image }}"
|
||||
},
|
||||
{
|
||||
name: "table",
|
||||
action: EasyMDE.drawTable,
|
||||
className: "fa-solid fa-table",
|
||||
className: "fa fa-table",
|
||||
title: "{{ translations.table }}"
|
||||
},
|
||||
"|",
|
||||
{
|
||||
name: "clean-block",
|
||||
action: EasyMDE.cleanBlock,
|
||||
className: "fa-solid fa-eraser",
|
||||
className: "fa fa-eraser fa-clean-block",
|
||||
title: "{{ translations.clean_block }}"
|
||||
},
|
||||
"|",
|
||||
{
|
||||
name: "preview",
|
||||
action: EasyMDE.togglePreview,
|
||||
className: "fa-solid fa-eye no-disable",
|
||||
className: "fa fa-eye no-disable",
|
||||
title: "{{ translations.preview }}"
|
||||
},
|
||||
{
|
||||
name: "side-by-side",
|
||||
action: EasyMDE.toggleSideBySide,
|
||||
className: "fa-solid fa-columns no-disable no-mobile",
|
||||
className: "fa fa-columns no-disable no-mobile",
|
||||
title: "{{ translations.side_by_side }}"
|
||||
},
|
||||
{
|
||||
name: "fullscreen",
|
||||
action: EasyMDE.toggleFullScreen,
|
||||
className: "fa-solid fa-arrows-alt no-disable no-mobile",
|
||||
className: "fa fa-arrows-alt no-disable no-mobile",
|
||||
title: "{{ translations.fullscreen }}"
|
||||
},
|
||||
"|",
|
||||
{
|
||||
name: "guide",
|
||||
action: "/page/Aide_sur_la_syntaxe",
|
||||
className: "fa-solid fa-question-circle",
|
||||
className: "fa fa-question-circle",
|
||||
title: "{{ translations.guide }}"
|
||||
},
|
||||
]
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
{% if user_registered %}
|
||||
{% 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 %}<br>
|
||||
{% trans %}You successfully registered and you will soon receive a confirmation mail.{% endtrans %}<br>
|
||||
{% trans username=user_registered.username %}Your username is {{ username }}.{% endtrans %}<br>
|
||||
|
||||
{% else %}
|
||||
|
@ -41,11 +41,11 @@
|
||||
{% set refilled = customer.refillings.exists() %}
|
||||
{% if bought or refilled %}
|
||||
{% if bought %}
|
||||
<h5>{% trans %}Account buyings{% endtrans %}</h5>
|
||||
<h5>{% trans %}Account purchases{% endtrans %}</h5>
|
||||
{{ monthly(buyings_month) }}
|
||||
{% endif %}
|
||||
{% if refilled %}
|
||||
<h5>{% trans %}Refillings{% endtrans %}</h5>
|
||||
<h5>{% trans %}Reloads{% endtrans %}</h5>
|
||||
{{ monthly(refilling_month) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
@ -10,7 +10,7 @@
|
||||
<p>{% trans %}Amount: {% endtrans %}{{ customer.amount }} €</p>
|
||||
<p><a href="{{ url('core:user_account', user_id=profile.id) }}">{% trans %}Back{% endtrans %}</a></p>
|
||||
{% if customer.buyings.exists() %}
|
||||
<h4>{% trans %}Account buyings{% endtrans %}</h4>
|
||||
<h4>{% trans %}Account purchases{% endtrans %}</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -43,7 +43,7 @@
|
||||
</table>
|
||||
{% endif %}
|
||||
{% if customer.refillings.exists() %}
|
||||
<h4>{% trans %}Refillings{% endtrans %}</h4>
|
||||
<h4>{% trans %}Reloads{% endtrans %}</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -165,8 +165,8 @@
|
||||
<a href="{{ url('subscription:subscription') }}?member={{ profile.id }}">{% trans %}New subscription{% endtrans
|
||||
%}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<br>
|
||||
{% if profile.was_subscribed and (user == profile or user.can_read_subscription_history)%}
|
||||
@ -176,7 +176,7 @@
|
||||
{% trans %}Subscription history{% endtrans %}
|
||||
</span>
|
||||
<span class="collapse-header-icon" :class="{'reverse': collapsed}">
|
||||
<i class="fa-sharp fa-solid fa-caret-down"></i>
|
||||
<i class="fa fa-caret-down"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="collapse-body" x-show="collapsed" x-transition.scale.origin.top>
|
||||
@ -201,6 +201,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr>
|
||||
<div>
|
||||
{% if user.is_root or user.is_board_member %}
|
||||
@ -213,36 +214,25 @@
|
||||
{% if profile.gifts.exists() %}
|
||||
{% set gifts = profile.gifts.order_by("-date")|list %}
|
||||
<br>
|
||||
|
||||
<div class="collapse" :class="{'shadow': collapsed}" x-data="{collapsed: false}" x-cloak>
|
||||
<div class="collapse-header clickable" @click="collapsed = !collapsed">
|
||||
<span class="collapse-header-text">
|
||||
{% trans %}Last given gift :{% endtrans %} {{ gifts[0] }}
|
||||
</span>
|
||||
<span class="collapse-header-icon" :class="{'reverse': collapsed}">
|
||||
<i class="fa-solid fa-caret-down"></i>
|
||||
<i class="fa fa-caret-down"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="collapse-body" x-show="collapsed" x-transition.scale.origin.top>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Subscription start{% endtrans %}</th>
|
||||
<th>{% trans %}Subscription end{% endtrans %}</th>
|
||||
<th>{% trans %}Subscription type{% endtrans %}</th>
|
||||
<th>{% trans %}Payment method{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for sub in profile.subscriptions.all() %}
|
||||
<tr>
|
||||
<td>{{ sub.subscription_start }}</td>
|
||||
<td>{{ sub.subscription_end }}</td>
|
||||
<td>{{ sub.subscription_type }}</td>
|
||||
<td>{{ sub.get_payment_method_display() }}</td>
|
||||
</tr>
|
||||
<ul>
|
||||
{% for gift in gifts %}
|
||||
<li>{{ gift }}
|
||||
<a href="{{ url('core:user_gift_delete', user_id=profile.id, gift_id=gift.id) }}">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<em>{% trans %}No gift given yet{% endtrans %}</em>
|
||||
|
@ -15,17 +15,18 @@
|
||||
#
|
||||
|
||||
import os
|
||||
from datetime import timedelta
|
||||
from datetime import date, timedelta
|
||||
|
||||
import freezegun
|
||||
from django.core.cache import cache
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.core.management import call_command
|
||||
from django.utils.timezone import now
|
||||
|
||||
from club.models import Membership
|
||||
from core.models import User, Group, Page, AnonymousUser
|
||||
from core.markdown import markdown
|
||||
from core.models import AnonymousUser, Group, Page, User
|
||||
from core.utils import get_semester_code, get_start_of_semester
|
||||
from sith import settings
|
||||
|
||||
"""
|
||||
@ -597,15 +598,95 @@ class UserIsInGroupTest(TestCase):
|
||||
Test that when a user is removed from a group,
|
||||
the is_in_group_method return False when calling it again
|
||||
"""
|
||||
# testing with pk
|
||||
self.toto.groups.add(self.com_admin.pk)
|
||||
self.assertTrue(self.toto.is_in_group(pk=self.com_admin.pk))
|
||||
|
||||
self.toto.groups.remove(self.com_admin.pk)
|
||||
self.assertFalse(self.toto.is_in_group(pk=self.com_admin.pk))
|
||||
|
||||
# testing with name
|
||||
self.toto.groups.add(self.sas_admin.pk)
|
||||
self.assertTrue(self.toto.is_in_group(name="SAS admin"))
|
||||
|
||||
self.toto.groups.remove(self.sas_admin.pk)
|
||||
self.assertFalse(self.toto.is_in_group(name="SAS admin"))
|
||||
|
||||
def test_not_existing_group(self):
|
||||
"""
|
||||
Test that searching for a not existing group
|
||||
returns False
|
||||
"""
|
||||
self.assertFalse(self.skia.is_in_group(name="This doesn't exist"))
|
||||
|
||||
|
||||
class DateUtilsTest(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.autumn_month = settings.SITH_SEMESTER_START_AUTUMN[0]
|
||||
cls.autumn_day = settings.SITH_SEMESTER_START_AUTUMN[1]
|
||||
cls.spring_month = settings.SITH_SEMESTER_START_SPRING[0]
|
||||
cls.spring_day = settings.SITH_SEMESTER_START_SPRING[1]
|
||||
|
||||
cls.autumn_semester_january = date(2025, 1, 4)
|
||||
cls.autumn_semester_september = date(2024, 9, 4)
|
||||
cls.autumn_first_day = date(2024, cls.autumn_month, cls.autumn_day)
|
||||
|
||||
cls.spring_semester_march = date(2023, 3, 4)
|
||||
cls.spring_first_day = date(2023, cls.spring_month, cls.spring_day)
|
||||
|
||||
def test_get_semester(self):
|
||||
"""
|
||||
Test that the get_semester function returns the correct semester string
|
||||
"""
|
||||
self.assertEqual(get_semester_code(self.autumn_semester_january), "A24")
|
||||
self.assertEqual(get_semester_code(self.autumn_semester_september), "A24")
|
||||
self.assertEqual(get_semester_code(self.autumn_first_day), "A24")
|
||||
|
||||
self.assertEqual(get_semester_code(self.spring_semester_march), "P23")
|
||||
self.assertEqual(get_semester_code(self.spring_first_day), "P23")
|
||||
|
||||
def test_get_start_of_semester_fixed_date(self):
|
||||
"""
|
||||
Test that the get_start_of_semester correctly the starting date of the semester.
|
||||
"""
|
||||
automn_2024 = date(2024, self.autumn_month, self.autumn_day)
|
||||
self.assertEqual(
|
||||
get_start_of_semester(self.autumn_semester_january), automn_2024
|
||||
)
|
||||
self.assertEqual(
|
||||
get_start_of_semester(self.autumn_semester_september), automn_2024
|
||||
)
|
||||
self.assertEqual(get_start_of_semester(self.autumn_first_day), automn_2024)
|
||||
|
||||
spring_2023 = date(2023, self.spring_month, self.spring_day)
|
||||
self.assertEqual(get_start_of_semester(self.spring_semester_march), spring_2023)
|
||||
self.assertEqual(get_start_of_semester(self.spring_first_day), spring_2023)
|
||||
|
||||
def test_get_start_of_semester_today(self):
|
||||
"""
|
||||
Test that the get_start_of_semester returns the start of the current semester
|
||||
when no date is given
|
||||
"""
|
||||
with freezegun.freeze_time(self.autumn_semester_september):
|
||||
self.assertEqual(get_start_of_semester(), self.autumn_first_day)
|
||||
|
||||
with freezegun.freeze_time(self.spring_semester_march):
|
||||
self.assertEqual(get_start_of_semester(), self.spring_first_day)
|
||||
|
||||
def test_get_start_of_semester_changing_date(self):
|
||||
"""
|
||||
Test that the get_start_of_semester correctly gives the starting date of the semester,
|
||||
even when the semester changes while the server isn't restarted.
|
||||
"""
|
||||
spring_2023 = date(2023, self.spring_month, self.spring_day)
|
||||
autumn_2023 = date(2023, self.autumn_month, self.autumn_day)
|
||||
mid_spring = spring_2023 + timedelta(days=45)
|
||||
mid_autumn = autumn_2023 + timedelta(days=45)
|
||||
|
||||
with freezegun.freeze_time(mid_spring) as frozen_time:
|
||||
self.assertEqual(get_start_of_semester(), spring_2023)
|
||||
|
||||
# forward time to the middle of the next semester
|
||||
frozen_time.move_to(mid_autumn)
|
||||
self.assertEqual(get_start_of_semester(), autumn_2023)
|
||||
|
@ -15,20 +15,19 @@
|
||||
#
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
# Image utils
|
||||
|
||||
from io import BytesIO
|
||||
import subprocess
|
||||
from datetime import date
|
||||
|
||||
from PIL import ExifTags
|
||||
# Image utils
|
||||
from io import BytesIO
|
||||
from typing import Optional
|
||||
|
||||
import PIL
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.base import ContentFile
|
||||
from PIL import ExifTags
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
def get_git_revision_short_hash() -> str:
|
||||
@ -44,34 +43,54 @@ def get_git_revision_short_hash() -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def get_start_of_semester(d=date.today()):
|
||||
def get_start_of_semester(today: Optional[date] = None) -> date:
|
||||
"""
|
||||
This function computes the start date of the semester with respect to the given date (default is today),
|
||||
and the start date given in settings.SITH_START_DATE.
|
||||
It takes the nearest past start date.
|
||||
Exemples: with SITH_START_DATE = (8, 15)
|
||||
Today -> Start date
|
||||
2015-03-17 -> 2015-02-15
|
||||
2015-01-11 -> 2014-08-15
|
||||
Return the date of the start of the semester of the given date.
|
||||
If no date is given, return the start date of the current semester.
|
||||
|
||||
The current semester is computed as follows:
|
||||
|
||||
- If the date is between 15/08 and 31/12 => Autumn semester.
|
||||
- If the date is between 01/01 and 15/02 => Autumn semester of the previous year.
|
||||
- If the date is between 15/02 and 15/08 => Spring semester
|
||||
|
||||
:param today: the date to use to compute the semester. If None, use today's date.
|
||||
:return: the date of the start of the semester
|
||||
"""
|
||||
today = d
|
||||
year = today.year
|
||||
start = date(year, settings.SITH_START_DATE[0], settings.SITH_START_DATE[1])
|
||||
start2 = start.replace(month=(start.month + 6) % 12)
|
||||
spring, autumn = min(start, start2), max(start, start2)
|
||||
if today > autumn: # autumn semester
|
||||
if today is None:
|
||||
today = timezone.now().date()
|
||||
|
||||
autumn = date(today.year, *settings.SITH_SEMESTER_START_AUTUMN)
|
||||
spring = date(today.year, *settings.SITH_SEMESTER_START_SPRING)
|
||||
|
||||
if today >= autumn: # between 15/08 (included) and 31/12 -> autumn semester
|
||||
return autumn
|
||||
if today > spring: # spring semester
|
||||
if today >= spring: # between 15/02 (included) and 15/08 -> spring semester
|
||||
return spring
|
||||
return autumn.replace(year=year - 1) # autumn semester of last year
|
||||
# between 01/01 and 15/02 -> autumn semester of the previous year
|
||||
return autumn.replace(year=autumn.year - 1)
|
||||
|
||||
|
||||
def get_semester(d=date.today()):
|
||||
def get_semester_code(d: Optional[date] = None) -> str:
|
||||
"""
|
||||
Return the semester code of the given date.
|
||||
If no date is given, return the semester code of the current semester.
|
||||
|
||||
The semester code is an upper letter (A for autumn, P for spring),
|
||||
followed by the last two digits of the year.
|
||||
For example, the autumn semester of 2018 is "A18".
|
||||
|
||||
:param d: the date to use to compute the semester. If None, use today's date.
|
||||
:return: the semester code corresponding to the given date
|
||||
"""
|
||||
if d is None:
|
||||
d = timezone.now().date()
|
||||
|
||||
start = get_start_of_semester(d)
|
||||
if start.month <= 6:
|
||||
return "P" + str(start.year)[-2:]
|
||||
else:
|
||||
|
||||
if (start.month, start.day) == settings.SITH_SEMESTER_START_AUTUMN:
|
||||
return "A" + str(start.year)[-2:]
|
||||
return "P" + str(start.year)[-2:]
|
||||
|
||||
|
||||
def file_exist(path):
|
||||
|
@ -15,7 +15,7 @@
|
||||
#
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Tuple
|
||||
from typing import Tuple, Optional
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import F, Value, Sum, QuerySet, OuterRef, Exists
|
||||
@ -536,7 +536,7 @@ class Counter(models.Model):
|
||||
.order_by("-perm_sum")
|
||||
)
|
||||
|
||||
def get_top_customers(self, since=get_start_of_semester()) -> QuerySet:
|
||||
def get_top_customers(self, since: Optional[date] = None) -> QuerySet:
|
||||
"""
|
||||
Return a QuerySet querying the money spent by customers of this counter
|
||||
since the specified date, ordered by descending amount of money spent.
|
||||
@ -546,6 +546,8 @@ class Counter(models.Model):
|
||||
- the nickname of the customer
|
||||
- the amount of money spent by the customer
|
||||
"""
|
||||
if since is None:
|
||||
since = get_start_of_semester()
|
||||
return (
|
||||
self.sellings.filter(date__gte=since)
|
||||
.annotate(
|
||||
@ -557,7 +559,8 @@ class Counter(models.Model):
|
||||
)
|
||||
.annotate(nickname=F("customer__user__nick_name"))
|
||||
.annotate(promo=F("customer__user__promo"))
|
||||
.values("customer__user", "name", "nickname")
|
||||
.annotate(user=F("customer__user"))
|
||||
.values("user", "promo", "name", "nickname")
|
||||
.annotate(
|
||||
selling_sum=Sum(
|
||||
F("unit_price") * F("quantity"), output_field=CurrencyField()
|
||||
@ -567,15 +570,17 @@ class Counter(models.Model):
|
||||
.order_by("-selling_sum")
|
||||
)
|
||||
|
||||
def get_total_sales(self, since=get_start_of_semester()) -> CurrencyField:
|
||||
def get_total_sales(self, since=None) -> CurrencyField:
|
||||
"""
|
||||
Compute and return the total turnover of this counter
|
||||
since the date specified in parameter (by default, since the start of the current
|
||||
semester)
|
||||
:param since: timestamp from which to perform the calculation
|
||||
:type since: datetime | date
|
||||
:type since: datetime | date | None
|
||||
:return: Total revenue earned at this counter
|
||||
"""
|
||||
if since is None:
|
||||
since = get_start_of_semester()
|
||||
if isinstance(since, date):
|
||||
since = datetime.combine(since, datetime.min.time())
|
||||
total = self.sellings.filter(date__gte=since).aggregate(
|
||||
|
@ -28,15 +28,15 @@
|
||||
<h5>{% trans %}Legend{% endtrans %}</h5>
|
||||
<div class="activity-description">
|
||||
<div>
|
||||
<i class="fa-solid fa-check" style="color: #2ecc71"></i>
|
||||
<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-solid fa-question" style="color: #f39c12"></i>
|
||||
<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-solid fa-xmark" style="color: #eb2f06"></i>
|
||||
<i class="fa fa-times" style="color: #eb2f06"></i>
|
||||
<span>{% trans %}counter is not open : no one is connected{% endtrans %}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@
|
||||
{{ form }}
|
||||
<p><input type="submit" value="{% trans %}Show{% endtrans %}" /></p>
|
||||
</form>
|
||||
<h6>{% trans %}Refillings{% endtrans %}</h6>
|
||||
<h6>{% trans %}Reloads{% endtrans %}</h6>
|
||||
<p>
|
||||
{% for b,s in refilling_sums.items() %}
|
||||
{{ b }}: {{ s }} €<br/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
{% endif %}
|
||||
{% if user.is_owner(c) %}
|
||||
<a href="{{ url('counter:prop_admin', counter_id=c.id) }}">{% trans %}Props{% endtrans %}</a> -
|
||||
<a href="{{ url('counter:refilling_list', counter_id=c.id) }}">{% trans %}Refillings list{% endtrans %}</a>
|
||||
<a href="{{ url('counter:refilling_list', counter_id=c.id) }}">{% trans %}Reloads list{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
@ -41,7 +41,7 @@
|
||||
{% endif %}
|
||||
{% if user.is_owner(c) %}
|
||||
<a href="{{ url('counter:prop_admin', counter_id=c.id) }}">{% trans %}Props{% endtrans %}</a> -
|
||||
<a href="{{ url('counter:refilling_list', counter_id=c.id) }}">{% trans %}Refillings list{% endtrans %}</a>
|
||||
<a href="{{ url('counter:refilling_list', counter_id=c.id) }}">{% trans %}Reloads list{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
@ -21,7 +21,7 @@
|
||||
{% block content %}
|
||||
<h3>{% trans counter_name=counter %}{{ counter_name }} counter{% endtrans %}</h3>
|
||||
<div>
|
||||
<h3>{% trans %}Sellings{% endtrans %}</h3>
|
||||
<h3>{% trans %}Sales{% endtrans %}</h3>
|
||||
{% if last_basket %}
|
||||
<h4>{% trans %}Last selling: {% endtrans %}</h4>
|
||||
<p>{% trans %}Client: {% endtrans %}{{ last_customer }} - {% trans %}New amount: {% endtrans %}{{ new_customer_amount }} €.</p>
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans counter_name=counter %}{{ counter_name }} last operations{% endtrans %}</h3>
|
||||
<h4>{% trans %}Refillings{% endtrans %}</h4>
|
||||
<h4>{% trans %}Reloads{% endtrans %}</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -38,7 +38,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4>{% trans %}Sellings{% endtrans %}</h4>
|
||||
<h4>{% trans %}Sales{% endtrans %}</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -2,7 +2,7 @@
|
||||
{% from 'core/macros.jinja' import paginate %}
|
||||
|
||||
{% block title %}
|
||||
{%- trans %}Refillings list{% endtrans %} -- {{ counter.name }}
|
||||
{%- trans %}Reloads list{% endtrans %} -- {{ counter.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -11,7 +11,9 @@
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans counter_name=counter %}{{ counter_name }} stats{% endtrans %}</h3>
|
||||
<h4>{% trans counter_name=counter.name %}Top 100 {{ counter_name }}{% endtrans %}</h4>
|
||||
<h4>
|
||||
{% trans counter_name=counter.name %}Top 100 {{ counter_name }}{% endtrans %} ({{ current_semester }})
|
||||
</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -35,7 +37,9 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4>{% trans counter_name=counter.name %}Top 100 barman {{ counter_name }}{% endtrans %}</h4>
|
||||
<h4>
|
||||
{% trans counter_name=counter.name %}Top 100 barman {{ counter_name }}{% endtrans %} ({{ current_semester }})
|
||||
</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -13,6 +13,7 @@
|
||||
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||
#
|
||||
#
|
||||
from datetime import date, timedelta
|
||||
import json
|
||||
import re
|
||||
import string
|
||||
@ -322,42 +323,49 @@ class CounterStatsTest(TestCase):
|
||||
Test the result of Counter.get_top_customers() is correct
|
||||
"""
|
||||
top = iter(self.counter.get_top_customers())
|
||||
self.assertEqual(
|
||||
next(top),
|
||||
expected_results = [
|
||||
{
|
||||
"customer__user": self.sli.id,
|
||||
"user": self.sli.id,
|
||||
"name": f"{self.sli.first_name} {self.sli.last_name}",
|
||||
"promo": self.sli.promo,
|
||||
"nickname": self.sli.nick_name,
|
||||
"selling_sum": 2000,
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
next(top),
|
||||
{
|
||||
"customer__user": self.skia.id,
|
||||
"user": self.skia.id,
|
||||
"name": f"{self.skia.first_name} {self.skia.last_name}",
|
||||
"promo": self.skia.promo,
|
||||
"nickname": self.skia.nick_name,
|
||||
"selling_sum": 1000,
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
next(top),
|
||||
{
|
||||
"customer__user": self.krophil.id,
|
||||
"user": self.krophil.id,
|
||||
"name": f"{self.krophil.first_name} {self.krophil.last_name}",
|
||||
"promo": self.krophil.promo,
|
||||
"nickname": self.krophil.nick_name,
|
||||
"selling_sum": 100,
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
next(top),
|
||||
{
|
||||
"customer__user": self.root.id,
|
||||
"user": self.root.id,
|
||||
"name": f"{self.root.first_name} {self.root.last_name}",
|
||||
"promo": self.root.promo,
|
||||
"nickname": self.root.nick_name,
|
||||
"selling_sum": 2,
|
||||
},
|
||||
]
|
||||
|
||||
for result in expected_results:
|
||||
self.assertEqual(
|
||||
next(top),
|
||||
{
|
||||
"user": result["user"],
|
||||
"name": result["name"],
|
||||
"promo": result["promo"],
|
||||
"nickname": result["nickname"],
|
||||
"selling_sum": result["selling_sum"],
|
||||
},
|
||||
)
|
||||
|
||||
self.assertIsNone(next(top, None))
|
||||
|
||||
|
||||
|
@ -48,7 +48,7 @@ import pytz
|
||||
from datetime import timedelta, datetime
|
||||
from http import HTTPStatus
|
||||
|
||||
from core.utils import get_start_of_semester
|
||||
from core.utils import get_start_of_semester, get_semester_code
|
||||
from core.views import CanViewMixin, TabedViewMixin, CanEditMixin
|
||||
from core.views.forms import LoginForm
|
||||
from core.models import User
|
||||
@ -1354,13 +1354,14 @@ class CounterStatView(DetailView, CounterAdminMixin):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""Add stats to the context"""
|
||||
counter = self.object
|
||||
counter: Counter = self.object
|
||||
semester_start = get_start_of_semester()
|
||||
office_hours = counter.get_top_barmen()
|
||||
kwargs = super(CounterStatView, self).get_context_data(**kwargs)
|
||||
kwargs.update(
|
||||
{
|
||||
"counter": counter,
|
||||
"current_semester": get_semester_code(),
|
||||
"total_sellings": counter.get_total_sales(since=semester_start),
|
||||
"top_customers": counter.get_top_customers(since=semester_start)[:100],
|
||||
"top_barman": office_hours[:100],
|
||||
|
@ -47,9 +47,9 @@
|
||||
<template x-for="item in items" :key="item.id">
|
||||
<li class="item-row" x-show="item.quantity > 0">
|
||||
<div class="item-quantity">
|
||||
<i class="fa-solid fa-minus"></i>
|
||||
<i class="fa fa-minus fa-xs" @click="remove(item.id)"></i>
|
||||
<span x-text="item.quantity"></span>
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
<i class="fa fa-plus" @click="add(item)"></i>
|
||||
</div>
|
||||
<span class="item-name" x-text="item.name"></span>
|
||||
<span class="item-price" x-text="(item.unit_price * item.quantity).toFixed(2) + ' €'"></span>
|
||||
@ -63,13 +63,13 @@
|
||||
</ul>
|
||||
<div class="catalog-buttons">
|
||||
<button @click="clear_basket()" class="clear">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
<i class="fa fa-trash"></i>
|
||||
{% trans %}Clear{% endtrans %}
|
||||
</button>
|
||||
<form method="get" action="{{ url('eboutic:command') }}">
|
||||
{% csrf_token %}
|
||||
<button class="validate">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
<i class="fa fa-check"></i>
|
||||
<input type="submit" value="{% trans %}Validate{% endtrans %}"/>
|
||||
</button>
|
||||
</form>
|
||||
@ -85,7 +85,7 @@
|
||||
</a>
|
||||
</span>
|
||||
<span class="clickable" @click="show_alert = false">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
<i class="fa fa-close"></i>
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -108,7 +108,7 @@
|
||||
{% if p.icon %}
|
||||
<img class="product-image" src="{{ p.icon.url }}" alt="image de {{ p.name }}">
|
||||
{% else %}
|
||||
<i class="fa-solid fa-image product-image"></i>
|
||||
<i class="fa fa-2x fa-picture-o product-image" ></i>
|
||||
{% endif %}
|
||||
<div class="product-description">
|
||||
<h4>{{ p.name }}</h4>
|
||||
@ -123,19 +123,6 @@
|
||||
{% else %}
|
||||
<p>{% trans %}There are no items available for sale{% endtrans %}</p>
|
||||
{% endfor %}
|
||||
|
||||
<h3>{% trans %}Partnership Eurockéennes 2023{% endtrans %}</h3>
|
||||
{% if user.is_subscribed %}
|
||||
<a title="Logiciel billetterie en ligne"
|
||||
href="https://widget.weezevent.com/ticket/a203b986-73b0-4e63-b18a-b7c8bad986b7?id_evenement=915745&locale=fr-FR&code=71348"
|
||||
class="weezevent-widget-integration" target="_blank"
|
||||
data-src="https://widget.weezevent.com/ticket/a203b986-73b0-4e63-b18a-b7c8bad986b7?id_evenement=915745&locale=fr-FR&code=71348"
|
||||
data-width="650" data-height="600" data-resize="1" data-nopb="0" data-type="neo" data-width_auto="1"
|
||||
data-noscroll="0" data-id="915745">Billetterie Weezevent</a>
|
||||
<script type="text/javascript" src="https://widget.weezevent.com/weez.js" async defer></script>
|
||||
{% else %}
|
||||
<div>{% trans %}You must be a contributor to access the Eurockéennes ticketing service.{% endtrans %}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -60,7 +60,7 @@
|
||||
{% trans %}Edit billing information{% endtrans %}
|
||||
</span>
|
||||
<span class="collapse-header-icon" :class="{'reverse': collapsed}">
|
||||
<i class="fa-sharp fa-solid fa-caret-down"></i>
|
||||
<i class="fa fa-caret-down"></i>
|
||||
</span>
|
||||
</div>
|
||||
<form class="collapse-body" id="billing_info_form" method="post"
|
||||
@ -78,7 +78,7 @@
|
||||
</template>
|
||||
</div>
|
||||
<div class="clickable" @click="errors = []">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
<i class="fa fa-close"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div x-show="successful" class="alert alert-green" x-transition>
|
||||
@ -86,7 +86,7 @@
|
||||
Informations de facturation enregistrées
|
||||
</div>
|
||||
<div class="clickable" @click="successful = false">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
<i class="fa fa-close"></i>
|
||||
</div>
|
||||
</div>
|
||||
<input type="submit" class="btn btn-blue clickable"
|
||||
|
@ -82,18 +82,18 @@
|
||||
<a href="{{url('election:update_role', role_id=role.id)}}">✏️</a>
|
||||
<a href="{{url('election:delete_role', role_id=role.id)}}">❌</a>
|
||||
{%- if role == role_list.last() %}
|
||||
<button disabled><i class="fa-solid fa-arrow-down"></i></button>
|
||||
<button disabled><i class="fa-sharp fa-solid fa-caret-down"></i></button>
|
||||
<button disabled><i class="fa fa-arrow-down"></i></button>
|
||||
<button disabled><i class="fa fa-caret-down"></i></button>
|
||||
{%- else %}
|
||||
<button type="button" onclick="window.location.replace('?role={{ role.id }}&action=bottom');"><i class="fa-solid fa-arrow-down"></i></button>
|
||||
<button type="button" onclick="window.location.replace('?role={{ role.id }}&action=down');"><i class="fa-sharp fa-solid fa-caret-down"></i></button>
|
||||
<button type="button" onclick="window.location.replace('?role={{ role.id }}&action=bottom');"><i class="fa fa-arrow-down"></i></button>
|
||||
<button type="button" onclick="window.location.replace('?role={{ role.id }}&action=down');"><i class="fa fa-caret-down"></i></button>
|
||||
{%- endif %}
|
||||
{% if role == role_list.first() %}
|
||||
<button disabled><i class="fa-solid fa-caret-up"></i></i></button>
|
||||
<button disabled><i class="fa-sharp fa-solid fa-arrow-up"></i></i></button>
|
||||
<button disabled><i class="fa fa-caret-up"></i></button>
|
||||
<button disabled><i class="fa fa-arrow-up"></i></button>
|
||||
{% else %}
|
||||
<button type="button" onclick="window.location.replace('?role={{ role.id }}&action=up');"><i class="fa-solid fa-caret-up"></i></i></button>
|
||||
<button type="button" onclick="window.location.replace('?role={{ role.id }}&action=top');"><i class="fa-sharp fa-solid fa-arrow-up"></i></i></button>
|
||||
<button type="button" onclick="window.location.replace('?role={{ role.id }}&action=up');"><i class="fa fa-caret-up"></i></button>
|
||||
<button type="button" onclick="window.location.replace('?role={{ role.id }}&action=top');"><i class="fa fa-arrow-up"></i></button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{%- endif -%}
|
||||
|
@ -63,7 +63,7 @@ msgstr "IBAN"
|
||||
|
||||
#: accounting/models.py:112
|
||||
msgid "account number"
|
||||
msgstr "numero de compte"
|
||||
msgstr "numéro de compte"
|
||||
|
||||
#: accounting/models.py:116 accounting/models.py:147 club/models.py:275
|
||||
#: com/models.py:75 com/models.py:266 com/models.py:302 counter/models.py:273
|
||||
@ -1173,7 +1173,7 @@ msgstr "Au"
|
||||
#: club/templates/club/club_sellings.jinja:5 club/views.py:154
|
||||
#: club/views.py:483 counter/templates/counter/counter_main.jinja:24
|
||||
#: counter/templates/counter/last_ops.jinja:41
|
||||
msgid "Sellings"
|
||||
msgid "Sales"
|
||||
msgstr "Ventes"
|
||||
|
||||
#: club/templates/club/club_sellings.jinja:9 club/templates/club/stats.jinja:19
|
||||
@ -1278,7 +1278,7 @@ msgid "Counters:"
|
||||
msgstr "Comptoirs : "
|
||||
|
||||
#: club/templates/club/club_tools.jinja:33
|
||||
msgid "Accouting: "
|
||||
msgid "Accounting: "
|
||||
msgstr "Comptabilité : "
|
||||
|
||||
#: club/templates/club/club_tools.jinja:41
|
||||
@ -1295,8 +1295,8 @@ msgid ""
|
||||
"not shown wait until moderation takes action"
|
||||
msgstr ""
|
||||
"Rappelez vous : les mailing listes doivent être modérées, si votre liste "
|
||||
"nouvellement créee n'est pas affichée, attendez jusqu'à qu'un modérateur "
|
||||
"entre en action"
|
||||
"nouvellement créée n'est pas affichée, attendez jusqu'à ce qu'un modérateur "
|
||||
"prenne une décision"
|
||||
|
||||
#: club/templates/club/mailing.jinja:13
|
||||
msgid "Mailing lists waiting for moderation"
|
||||
@ -1671,8 +1671,8 @@ msgid "Moderator: "
|
||||
msgstr "Modérateur : "
|
||||
|
||||
#: com/templates/com/news_detail.jinja:42
|
||||
msgid "Edit (will be remoderated)"
|
||||
msgstr "Éditer (sera resoumise à modération)"
|
||||
msgid "Edit (will be moderated again)"
|
||||
msgstr "Éditer (sera soumise de nouveau à la modération)"
|
||||
|
||||
#: com/templates/com/news_edit.jinja:6 com/templates/com/news_edit.jinja:29
|
||||
msgid "Edit news"
|
||||
@ -1680,7 +1680,7 @@ msgstr "Éditer la nouvelle"
|
||||
|
||||
#: com/templates/com/news_edit.jinja:39
|
||||
msgid "Notice: Information, election result - no date"
|
||||
msgstr "Information, resultat d'élection - sans date"
|
||||
msgstr "Information, résultat d'élection - sans date"
|
||||
|
||||
#: com/templates/com/news_edit.jinja:40
|
||||
msgid "Event: punctual event, associated with one date"
|
||||
@ -1951,7 +1951,7 @@ msgstr "T'es fou? Un événement ne peut pas finir avant même de commencer."
|
||||
|
||||
#: com/views.py:466
|
||||
msgid "Delete and save to regenerate"
|
||||
msgstr "Supprimer et sauver pour regénérer"
|
||||
msgstr "Supprimer et sauver pour régénérer"
|
||||
|
||||
#: com/views.py:481
|
||||
msgid "Weekmail of the "
|
||||
@ -2036,7 +2036,7 @@ msgid ""
|
||||
"Designates whether this user should be treated as active. Unselect this "
|
||||
"instead of deleting accounts."
|
||||
msgstr ""
|
||||
"Est-ce que l'utilisateur doit être traité comme actif. Déselectionnez au "
|
||||
"Est-ce que l'utilisateur doit être traité comme actif. Désélectionnez au "
|
||||
"lieu de supprimer les comptes."
|
||||
|
||||
#: core/models.py:185
|
||||
@ -2085,7 +2085,7 @@ msgstr "pronoms"
|
||||
|
||||
#: core/models.py:234
|
||||
msgid "tshirt size"
|
||||
msgstr "taille de tshirt"
|
||||
msgstr "taille de t-shirt"
|
||||
|
||||
#: core/models.py:237
|
||||
msgid "-"
|
||||
@ -2426,7 +2426,7 @@ msgstr "Voir plus"
|
||||
#: core/templates/core/base.jinja:122
|
||||
#: forum/templates/forum/last_unread.jinja:17
|
||||
msgid "Mark all as read"
|
||||
msgstr "Marquer tout commme lu"
|
||||
msgstr "Marquer tout comme lu"
|
||||
|
||||
#: core/templates/core/base.jinja:132
|
||||
msgid "Logout"
|
||||
@ -2440,33 +2440,17 @@ msgstr "Accueil"
|
||||
msgid "Associations & Clubs"
|
||||
msgstr "Associations & Clubs"
|
||||
|
||||
#: core/templates/core/base.jinja:173
|
||||
#: core/templates/core/base.jinja:204
|
||||
msgid "AE"
|
||||
msgstr "L'AE"
|
||||
|
||||
#: core/templates/core/base.jinja:174
|
||||
#: core/templates/core/base.jinja:205
|
||||
msgid "AE's clubs"
|
||||
msgstr "Les clubs de L'AE"
|
||||
|
||||
#: core/templates/core/base.jinja:175
|
||||
msgid "BdF"
|
||||
msgstr "Le BdF"
|
||||
|
||||
#: core/templates/core/base.jinja:176
|
||||
msgid "BDS"
|
||||
msgstr "Le BDS"
|
||||
|
||||
#: core/templates/core/base.jinja:177
|
||||
msgid "CETU"
|
||||
msgstr "Le CETU"
|
||||
|
||||
#: core/templates/core/base.jinja:178
|
||||
msgid "Doceo"
|
||||
msgstr "Doceo"
|
||||
|
||||
#: core/templates/core/base.jinja:179
|
||||
msgid "Positions"
|
||||
msgstr "Postes à pourvoir"
|
||||
#: core/templates/core/base.jinja:206
|
||||
msgid "Others UTBM's Associations"
|
||||
msgstr "Les autres associations de l'UTBM"
|
||||
|
||||
#: core/templates/core/base.jinja:187 core/templates/core/user_tools.jinja:118
|
||||
msgid "Elections"
|
||||
@ -2780,7 +2764,7 @@ msgstr "Cotisant jusqu'au %(subscription_end)s"
|
||||
|
||||
#: core/templates/core/macros.jinja:86 core/templates/core/user_edit.jinja:40
|
||||
msgid "Account number: "
|
||||
msgstr "Numero de compte : "
|
||||
msgstr "Numéro de compte : "
|
||||
|
||||
#: core/templates/core/macros.jinja:91 launderette/models.py:217
|
||||
msgid "Slot"
|
||||
@ -3004,7 +2988,7 @@ msgstr "Bienvenue, %(user_name)s!"
|
||||
|
||||
#: core/templates/core/register.jinja:10
|
||||
msgid ""
|
||||
"You successfully registred and you will soon receive a confirmation mail."
|
||||
"You successfully registered and you will soon receive a confirmation mail."
|
||||
msgstr ""
|
||||
"Vous vous êtes correctement enregistré, et vous devriez recevoir rapidement "
|
||||
"un email de confirmation."
|
||||
@ -3063,14 +3047,14 @@ msgstr "Compte utilisateur"
|
||||
|
||||
#: core/templates/core/user_account.jinja:44
|
||||
#: core/templates/core/user_account_detail.jinja:13
|
||||
msgid "Account buyings"
|
||||
msgstr "Achat sur compte utilisateur"
|
||||
msgid "Account purchases"
|
||||
msgstr "Achats du compte"
|
||||
|
||||
#: core/templates/core/user_account.jinja:48
|
||||
#: core/templates/core/user_account_detail.jinja:46
|
||||
#: counter/templates/counter/cash_summary_list.jinja:17
|
||||
#: counter/templates/counter/last_ops.jinja:16
|
||||
msgid "Refillings"
|
||||
msgid "Reloads"
|
||||
msgstr "Rechargements"
|
||||
|
||||
#: core/templates/core/user_account.jinja:53
|
||||
@ -4114,7 +4098,7 @@ msgstr "Nouveau comptoir"
|
||||
#: counter/templates/counter/counter_list.jinja:22
|
||||
#: counter/templates/counter/counter_list.jinja:44
|
||||
#: counter/templates/counter/refilling_list.jinja:5
|
||||
msgid "Refillings list"
|
||||
msgid "Reloads list"
|
||||
msgstr "Liste de rechargements"
|
||||
|
||||
#: counter/templates/counter/counter_list.jinja:27
|
||||
@ -5033,7 +5017,7 @@ msgid ""
|
||||
"The code of an UV must only contains uppercase characters without accent and "
|
||||
"numbers"
|
||||
msgstr ""
|
||||
"Le code d'une UV doit seulement contenire des caractères majuscule sans "
|
||||
"Le code d'une UV doit seulement contenir des caractères majuscule sans "
|
||||
"accents et nombres"
|
||||
|
||||
#: pedagogy/models.py:67
|
||||
@ -5058,7 +5042,7 @@ msgstr "département"
|
||||
|
||||
#: pedagogy/models.py:103
|
||||
msgid "objectives"
|
||||
msgstr "objecifs"
|
||||
msgstr "objectifs"
|
||||
|
||||
#: pedagogy/models.py:104
|
||||
msgid "program"
|
||||
@ -5094,7 +5078,7 @@ msgstr "heures TE"
|
||||
|
||||
#: pedagogy/models.py:217 pedagogy/models.py:291
|
||||
msgid "uv"
|
||||
msgstr "uv"
|
||||
msgstr "UE"
|
||||
|
||||
#: pedagogy/models.py:221
|
||||
msgid "global grade"
|
||||
@ -5153,7 +5137,7 @@ msgstr "%(credit_type)s"
|
||||
#: pedagogy/templates/pedagogy/guide.jinja:59
|
||||
#: pedagogy/templates/pedagogy/moderation.jinja:12
|
||||
msgid "UV"
|
||||
msgstr "UV"
|
||||
msgstr "UE"
|
||||
|
||||
#: pedagogy/templates/pedagogy/guide.jinja:61
|
||||
msgid "Department"
|
||||
@ -5253,8 +5237,8 @@ msgid "Key concepts"
|
||||
msgstr "Concepts clefs"
|
||||
|
||||
#: pedagogy/templates/pedagogy/uv_detail.jinja:79
|
||||
msgid "UV manager: "
|
||||
msgstr "Gestionnaire d'UV : "
|
||||
msgid "UE manager: "
|
||||
msgstr "Gestionnaire d'UE : "
|
||||
|
||||
#: pedagogy/templates/pedagogy/uv_detail.jinja:86 pedagogy/tests.py:453
|
||||
msgid ""
|
||||
@ -5284,23 +5268,23 @@ msgstr "Signaler ce commentaire"
|
||||
|
||||
#: pedagogy/templates/pedagogy/uv_edit.jinja:4
|
||||
#: pedagogy/templates/pedagogy/uv_edit.jinja:8
|
||||
msgid "Edit UV"
|
||||
msgstr "Éditer"
|
||||
msgid "Edit UE"
|
||||
msgstr "Éditer l'UE"
|
||||
|
||||
#: pedagogy/templates/pedagogy/uv_edit.jinja:27
|
||||
msgid "Import from UTBM"
|
||||
msgstr "Importer depuis l'UTBM"
|
||||
|
||||
#: pedagogy/templates/pedagogy/uv_edit.jinja:62
|
||||
msgid "Unknown UV code"
|
||||
msgstr "Code d'UV inconnu"
|
||||
msgid "Unknown UE code"
|
||||
msgstr "Code d'UE inconnu"
|
||||
|
||||
#: pedagogy/templates/pedagogy/uv_edit.jinja:77
|
||||
msgid "Successful autocomplete"
|
||||
msgstr "Autocomplétion réussite"
|
||||
|
||||
#: pedagogy/templates/pedagogy/uv_edit.jinja:80
|
||||
msgid "An error occured: "
|
||||
msgid "An error occurred: "
|
||||
msgstr "Une erreur est survenue : "
|
||||
|
||||
#: rootplace/templates/rootplace/delete_user_messages.jinja:8
|
||||
@ -5566,7 +5550,7 @@ msgstr "Automne et printemps"
|
||||
|
||||
#: sith/settings.py:448
|
||||
msgid "German"
|
||||
msgstr "Allemant"
|
||||
msgstr "Allemand"
|
||||
|
||||
#: sith/settings.py:449
|
||||
msgid "Spanish"
|
||||
@ -6362,11 +6346,3 @@ msgstr "Vous ne pouvez plus écrire de commentaires, la date est passée."
|
||||
#, python-format
|
||||
msgid "Maximum characters: %(max_length)s"
|
||||
msgstr "Nombre de caractères max: %(max_length)s"
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja:127
|
||||
msgid "Partnership Eurockéennes 2023"
|
||||
msgstr "Partenariat Eurockéennes 2023"
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja:137
|
||||
msgid "You must be a subscriber to access the Eurockéennes ticketing service."
|
||||
msgstr "Vous devez être cotisant pour pouvoir accéder à la billetterie des Eurockéennes."
|
||||
|
@ -45,8 +45,8 @@
|
||||
|
||||
<div class="radio-semester">
|
||||
<div class="radio-guide">
|
||||
<input type="checkbox" name="semester" id="radioAUTUMN" value="AUTUMN"><label for="radioAUTUMN"><i class="fa-solid fa-leaf"></i></label>
|
||||
<input type="checkbox" name="semester" id="radioSPRING" value="SPRING"><label for="radioSPRING"><i class="fa-solid fa-sun"></i></label>
|
||||
<input type="checkbox" name="semester" id="radioAUTUMN" value="AUTUMN"><label for="radioAUTUMN"><i class="fa fa-leaf"></i></label>
|
||||
<input type="checkbox" name="semester" id="radioSPRING" value="SPRING"><label for="radioSPRING"><i class="fa fa-sun-o"></i></label>
|
||||
<span><input type="checkbox" name="semester" id="radioAP" value="AUTUMN_AND_SPRING"><label for="radioAP">AP</label></span>
|
||||
</div>
|
||||
</div>
|
||||
@ -60,8 +60,8 @@
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Department{% endtrans %}</td>
|
||||
<td>{% trans %}Credit type{% endtrans %}</td>
|
||||
<td><i class="fa-solid fa-leaf"></i></td>
|
||||
<td><i class="fa-solid fa-sun"></i></td>
|
||||
<td><i class="fa fa-leaf"></i></td>
|
||||
<td><i class="fa fa-sun-o"></i></td>
|
||||
{% if can_create_uv(user) %}
|
||||
<td>{% trans %}Edit{% endtrans %}</td>
|
||||
<td>{% trans %}Delete{% endtrans %}</td>
|
||||
@ -77,12 +77,12 @@
|
||||
<td>{{ uv.credit_type }}</td>
|
||||
<td>
|
||||
{% if uv.semester in ["AUTUMN", "AUTUMN_AND_SPRING"] %}
|
||||
<i class="fa-solid fa-leaf"></i>
|
||||
<i class="fa fa-leaf"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if uv.semester in ["SPRING", "AUTUMN_AND_SPRING"] %}
|
||||
<i class="fa-solid fa-sun"></i>
|
||||
<i class="fa fa-sun-o"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if user.is_owner(uv) -%}
|
||||
@ -107,9 +107,9 @@
|
||||
var autumn = "";
|
||||
var spring = "";
|
||||
if (uv.semester == "AUTUMN" || uv.semester == "AUTUMN_AND_SPRING")
|
||||
autumn = "<i class='fa-solid fa-leaf'></i>";
|
||||
autumn = "<i class='fa fa-leaf'></i>";
|
||||
if (uv.semester == "SPRING" || uv.semester == "AUTUMN_AND_SPRING")
|
||||
spring = "<i class='fa-solid fa-sun'></i>";
|
||||
spring = "<i class='fa fa-sun-o'></i>";
|
||||
|
||||
var html = `
|
||||
<tr onclick="window.location.href = '${uv.absolute_url}';">
|
||||
|
@ -3,9 +3,9 @@
|
||||
{% if grade >= 0 %}
|
||||
{% for i in range(5) %}
|
||||
{% if i <= grade %}
|
||||
<span class="fa-solid fa-star pedagogy star-checked grade-with-star"></span>
|
||||
<span class="fa fa-star pedagogy star-checked grade-with-star"></span>
|
||||
{% else %}
|
||||
<span class="fa-solid fa-star pedagogy star-not-checked grade-with-star"></span>
|
||||
<span class="fa fa-star pedagogy star-not-checked grade-with-star"></span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<span class="pedagogy grade-without-star">{{ grade }}/5</span>
|
||||
|
@ -26,7 +26,7 @@
|
||||
stars[i].setAttribute("class", attrs + " unchecked");
|
||||
}
|
||||
' checked>
|
||||
<span class="fa-solid fa-xmark-circle"> {{ translations.do_not_vote }}</span>
|
||||
<span class="fa fa-times-circle"> {{ translations.do_not_vote }}</span>
|
||||
</label>
|
||||
|
||||
{# Star widget #}
|
||||
@ -46,7 +46,7 @@
|
||||
}
|
||||
}
|
||||
'>
|
||||
<i class="{{ widget.name }} fa-solid fa-star unchecked"></i>
|
||||
<i class="{{ widget.name }} fa fa-star unchecked"></i>
|
||||
</label>
|
||||
{% endfor %}
|
||||
|
||||
|
@ -76,7 +76,7 @@
|
||||
<p>{{ object.skills|markdown }}</p>
|
||||
<p><b>{% trans %}Key concepts{% endtrans %}</b></p>
|
||||
<p>{{ object.key_concepts|markdown }}</p>
|
||||
<p><b>{% trans %}UV manager: {% endtrans %}</b>{{ object.manager }}</p>
|
||||
<p><b>{% trans %}UE manager: {% endtrans %}</b>{{ object.manager }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -167,7 +167,7 @@
|
||||
|
||||
<div class="comment">
|
||||
<div class="anchor">
|
||||
<a href="{{ url('pedagogy:uv_detail', uv_id=uv.id) }}#{{ comment.id }}"><i class="fa-solid fa-paragraph"></i></a>
|
||||
<a href="{{ url('pedagogy:uv_detail', uv_id=uv.id) }}#{{ comment.id }}"><i class="fa fa-paragraph"></i></a>
|
||||
</div>
|
||||
{{ comment.comment|markdown }}
|
||||
</div>
|
||||
@ -206,8 +206,8 @@
|
||||
$("#return_noscript").hide();
|
||||
$("#return_js").show();
|
||||
var icons = {
|
||||
header: "fa-solid fa-toggle-on",
|
||||
activeHeader: "fa-solid fa-toggle-off"
|
||||
header: "fa fa-toggle-right",
|
||||
activeHeader: "fa fa-toggle-down"
|
||||
};
|
||||
$(function(){
|
||||
$("#leave_comment").accordion({
|
||||
|
@ -1,11 +1,11 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Edit UV{% endtrans %}
|
||||
{% trans %}Edit UE{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% trans %}Edit UV{% endtrans %}</h2>
|
||||
<h2>{% trans %}Edit UE{% endtrans %}</h2>
|
||||
<form action="" method="post" enctype="multipart/form-data" id="uv_edit">
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors() }}
|
||||
@ -59,7 +59,7 @@
|
||||
url: url,
|
||||
success: function(data, _, xhr) {
|
||||
if (xhr.status != 200) {
|
||||
createQuickNotif("{% trans %}Unknown UV code{% endtrans %}")
|
||||
createQuickNotif("{% trans %}Unknown UE code{% endtrans %}")
|
||||
return
|
||||
}
|
||||
for (let key in data) {
|
||||
@ -77,7 +77,7 @@
|
||||
createQuickNotif('{% trans %}Successful autocomplete{% endtrans %}')
|
||||
},
|
||||
error: function(_, _, statusMessage) {
|
||||
createQuickNotif('{% trans %}An error occured: {% endtrans %}' + statusMessage)
|
||||
createQuickNotif('{% trans %}An error occurred: {% endtrans %}' + statusMessage)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
140
poetry.lock
generated
140
poetry.lock
generated
@ -1,10 +1,9 @@
|
||||
# This file is automatically @generated by Poetry and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "alabaster"
|
||||
version = "0.7.12"
|
||||
description = "A configurable sidebar-enabled Sphinx theme"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -16,7 +15,6 @@ files = [
|
||||
name = "appnope"
|
||||
version = "0.1.3"
|
||||
description = "Disable App Nap on macOS >= 10.9"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -28,7 +26,6 @@ files = [
|
||||
name = "asgiref"
|
||||
version = "3.6.0"
|
||||
description = "ASGI specs, helper code, and adapters"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -43,7 +40,6 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
|
||||
name = "babel"
|
||||
version = "2.11.0"
|
||||
description = "Internationalization utilities"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -58,7 +54,6 @@ pytz = ">=2015.7"
|
||||
name = "backcall"
|
||||
version = "0.2.0"
|
||||
description = "Specifications for callback functions passed in to an API"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -70,7 +65,6 @@ files = [
|
||||
name = "black"
|
||||
version = "23.3.0"
|
||||
description = "The uncompromising code formatter."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -120,7 +114,6 @@ uvloop = ["uvloop (>=0.15.2)"]
|
||||
name = "certifi"
|
||||
version = "2022.12.7"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -132,7 +125,6 @@ files = [
|
||||
name = "cffi"
|
||||
version = "1.15.1"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -209,7 +201,6 @@ pycparser = "*"
|
||||
name = "charset-normalizer"
|
||||
version = "2.1.1"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.6.0"
|
||||
files = [
|
||||
@ -224,7 +215,6 @@ unicode-backport = ["unicodedata2"]
|
||||
name = "click"
|
||||
version = "8.1.3"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -239,7 +229,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
@ -251,7 +240,6 @@ files = [
|
||||
name = "coverage"
|
||||
version = "5.5"
|
||||
description = "Code coverage measurement for Python"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
files = [
|
||||
@ -316,7 +304,6 @@ toml = ["toml"]
|
||||
name = "cryptography"
|
||||
version = "40.0.1"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -358,7 +345,6 @@ tox = ["tox"]
|
||||
name = "decorator"
|
||||
version = "5.1.1"
|
||||
description = "Decorators for Humans"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -370,7 +356,6 @@ files = [
|
||||
name = "dict2xml"
|
||||
version = "1.7.3"
|
||||
description = "Small utility to convert a python dictionary into an XML string"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -385,7 +370,6 @@ tests = ["noseofyeti[black] (==2.4.1)", "pytest (==7.2.1)"]
|
||||
name = "django"
|
||||
version = "3.2.18"
|
||||
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -406,7 +390,6 @@ bcrypt = ["bcrypt"]
|
||||
name = "django-ajax-selects"
|
||||
version = "2.2.0"
|
||||
description = "Edit ForeignKey, ManyToManyField and CharField in Django Admin using jQuery UI AutoComplete."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -417,7 +400,6 @@ files = [
|
||||
name = "django-countries"
|
||||
version = "7.5.1"
|
||||
description = "Provides a country field for Django models."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -439,7 +421,6 @@ test = ["djangorestframework", "graphene-django", "pytest", "pytest-cov", "pytes
|
||||
name = "django-debug-toolbar"
|
||||
version = "4.0.0"
|
||||
description = "A configurable set of panels that display various debug information about the current request/response."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@ -455,7 +436,6 @@ sqlparse = ">=0.2"
|
||||
name = "django-haystack"
|
||||
version = "3.2.1"
|
||||
description = "Pluggable search for Django."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -472,7 +452,6 @@ elasticsearch = ["elasticsearch (>=5,<8)"]
|
||||
name = "django-jinja"
|
||||
version = "2.10.2"
|
||||
description = "Jinja2 templating language integrated in Django."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -486,21 +465,19 @@ jinja2 = ">=3"
|
||||
|
||||
[[package]]
|
||||
name = "django-ordered-model"
|
||||
version = "3.6"
|
||||
version = "3.7.4"
|
||||
description = "Allows Django models to be ordered and provides a simple admin interface for reordering them."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "django-ordered-model-3.6.tar.gz", hash = "sha256:62161a6bc51d8b402644854b257605d7b5183d01fd349826682a87e9227c05b5"},
|
||||
{file = "django_ordered_model-3.6-py3-none-any.whl", hash = "sha256:0006b111f472a2348f75554a4e77bee2b1f379a0f96726af6b1a3ebf3a950789"},
|
||||
{file = "django-ordered-model-3.7.4.tar.gz", hash = "sha256:f258b9762525c00a53009e82f8b8bf2a3aa315e8b453e281e8fdbbfe2b8cb3ba"},
|
||||
{file = "django_ordered_model-3.7.4-py3-none-any.whl", hash = "sha256:dfcd3183fe0749dad1c9971cba1d6240ce7328742a30ddc92feca41107bb241d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-phonenumber-field"
|
||||
version = "6.4.0"
|
||||
description = "An international phone number field for django models."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -519,7 +496,6 @@ phonenumberslite = ["phonenumberslite (>=7.0.2)"]
|
||||
name = "django-ranged-response"
|
||||
version = "0.2.0"
|
||||
description = "Modified Django FileResponse that adds Content-Range headers."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -533,7 +509,6 @@ django = "*"
|
||||
name = "django-simple-captcha"
|
||||
version = "0.5.17"
|
||||
description = "A very simple, yet powerful, Django captcha application"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -553,7 +528,6 @@ test = ["testfixtures"]
|
||||
name = "djangorestframework"
|
||||
version = "3.14.0"
|
||||
description = "Web APIs for Django, made easy."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -569,7 +543,6 @@ pytz = "*"
|
||||
name = "docutils"
|
||||
version = "0.17.1"
|
||||
description = "Docutils -- Python Documentation Utilities"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
@ -577,11 +550,24 @@ files = [
|
||||
{file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "freezegun"
|
||||
version = "1.2.2"
|
||||
description = "Let your Python tests travel through time"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "freezegun-1.2.2-py3-none-any.whl", hash = "sha256:ea1b963b993cb9ea195adbd893a48d573fda951b0da64f60883d7e988b606c9f"},
|
||||
{file = "freezegun-1.2.2.tar.gz", hash = "sha256:cd22d1ba06941384410cd967d8a99d5ae2442f57dfafeff2fda5de8dc5c05446"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
python-dateutil = ">=2.7"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.4"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -593,7 +579,6 @@ files = [
|
||||
name = "imagesize"
|
||||
version = "1.4.1"
|
||||
description = "Getting image size from png/jpeg/jpeg2000/gif file"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
@ -605,7 +590,6 @@ files = [
|
||||
name = "importlib-metadata"
|
||||
version = "6.0.0"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -625,7 +609,6 @@ testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packag
|
||||
name = "ipython"
|
||||
version = "7.34.0"
|
||||
description = "IPython: Productive Interactive Computing"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -662,7 +645,6 @@ test = ["ipykernel", "nbformat", "nose (>=0.10.1)", "numpy (>=1.17)", "pygments"
|
||||
name = "jedi"
|
||||
version = "0.18.2"
|
||||
description = "An autocompletion tool for Python that can be used for text editors."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -682,7 +664,6 @@ testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
|
||||
name = "jinja2"
|
||||
version = "3.1.2"
|
||||
description = "A very fast and expressive template engine."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -700,7 +681,6 @@ i18n = ["Babel (>=2.7)"]
|
||||
name = "libsass"
|
||||
version = "0.22.0"
|
||||
description = "Sass for Python: A straightforward binding of libsass for Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -715,7 +695,6 @@ files = [
|
||||
name = "markupsafe"
|
||||
version = "2.1.1"
|
||||
description = "Safely add untrusted strings to HTML/XML markup."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -765,7 +744,6 @@ files = [
|
||||
name = "matplotlib-inline"
|
||||
version = "0.1.6"
|
||||
description = "Inline Matplotlib backend for Jupyter"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -780,7 +758,6 @@ traitlets = "*"
|
||||
name = "mistune"
|
||||
version = "0.8.4"
|
||||
description = "The fastest markdown parser in pure Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -792,7 +769,6 @@ files = [
|
||||
name = "mypy-extensions"
|
||||
version = "0.4.3"
|
||||
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -804,7 +780,6 @@ files = [
|
||||
name = "packaging"
|
||||
version = "23.0"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -816,7 +791,6 @@ files = [
|
||||
name = "parso"
|
||||
version = "0.8.3"
|
||||
description = "A Python Parser"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -832,7 +806,6 @@ testing = ["docopt", "pytest (<6.0.0)"]
|
||||
name = "pathspec"
|
||||
version = "0.10.3"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -844,7 +817,6 @@ files = [
|
||||
name = "pexpect"
|
||||
version = "4.8.0"
|
||||
description = "Pexpect allows easy control of interactive console applications."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -859,7 +831,6 @@ ptyprocess = ">=0.5"
|
||||
name = "phonenumbers"
|
||||
version = "8.13.4"
|
||||
description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -871,7 +842,6 @@ files = [
|
||||
name = "pickleshare"
|
||||
version = "0.7.5"
|
||||
description = "Tiny 'shelve'-like database with concurrency support"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -883,7 +853,6 @@ files = [
|
||||
name = "pillow"
|
||||
version = "9.4.0"
|
||||
description = "Python Imaging Library (Fork)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -974,7 +943,6 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa
|
||||
name = "platformdirs"
|
||||
version = "2.6.2"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -990,7 +958,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-
|
||||
name = "prompt-toolkit"
|
||||
version = "3.0.36"
|
||||
description = "Library for building powerful interactive command lines in Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6.2"
|
||||
files = [
|
||||
@ -1005,7 +972,6 @@ wcwidth = "*"
|
||||
name = "psycopg2-binary"
|
||||
version = "2.9.3"
|
||||
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -1074,7 +1040,6 @@ files = [
|
||||
name = "ptyprocess"
|
||||
version = "0.7.0"
|
||||
description = "Run a subprocess in a pseudo terminal"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -1086,7 +1051,6 @@ files = [
|
||||
name = "pycparser"
|
||||
version = "2.21"
|
||||
description = "C parser in Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
@ -1098,7 +1062,6 @@ files = [
|
||||
name = "pygments"
|
||||
version = "2.14.0"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -1113,7 +1076,6 @@ plugins = ["importlib-metadata"]
|
||||
name = "pygraphviz"
|
||||
version = "1.10"
|
||||
description = "Python interface to Graphviz"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@ -1124,7 +1086,6 @@ files = [
|
||||
name = "pyopenssl"
|
||||
version = "23.1.1"
|
||||
description = "Python wrapper module around the OpenSSL library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -1143,7 +1104,6 @@ test = ["flaky", "pretend", "pytest (>=3.0.1)"]
|
||||
name = "python-dateutil"
|
||||
version = "2.8.2"
|
||||
description = "Extensions to the standard Python datetime module"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
files = [
|
||||
@ -1158,7 +1118,6 @@ six = ">=1.5"
|
||||
name = "pytz"
|
||||
version = "2021.3"
|
||||
description = "World timezone definitions, modern and historical"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -1170,7 +1129,6 @@ files = [
|
||||
name = "reportlab"
|
||||
version = "3.6.12"
|
||||
description = "The Reportlab Toolkit"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7,<4"
|
||||
files = [
|
||||
@ -1232,7 +1190,6 @@ rlpycairo = ["rlPyCairo (>=0.1.0)"]
|
||||
name = "requests"
|
||||
version = "2.28.1"
|
||||
description = "Python HTTP for Humans."
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.7, <4"
|
||||
files = [
|
||||
@ -1254,7 +1211,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
name = "sentry-sdk"
|
||||
version = "1.21.0"
|
||||
description = "Python client for Sentry (https://sentry.io)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -1296,7 +1252,6 @@ tornado = ["tornado (>=5)"]
|
||||
name = "setuptools"
|
||||
version = "65.6.3"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -1313,7 +1268,6 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
files = [
|
||||
@ -1325,7 +1279,6 @@ files = [
|
||||
name = "snowballstemmer"
|
||||
version = "2.2.0"
|
||||
description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -1337,7 +1290,6 @@ files = [
|
||||
name = "sphinx"
|
||||
version = "4.5.0"
|
||||
description = "Python documentation generator"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -1373,7 +1325,6 @@ test = ["cython", "html5lib", "pytest", "pytest-cov", "typed-ast"]
|
||||
name = "sphinx-copybutton"
|
||||
version = "0.4.0"
|
||||
description = "Add a copy button to each of your code cells."
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -1392,7 +1343,6 @@ rtd = ["ipython", "sphinx", "sphinx-book-theme"]
|
||||
name = "sphinx-rtd-theme"
|
||||
version = "1.1.1"
|
||||
description = "Read the Docs theme for Sphinx"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
|
||||
files = [
|
||||
@ -1411,7 +1361,6 @@ dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"]
|
||||
name = "sphinxcontrib-applehelp"
|
||||
version = "1.0.3"
|
||||
description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@ -1427,7 +1376,6 @@ test = ["pytest"]
|
||||
name = "sphinxcontrib-devhelp"
|
||||
version = "1.0.2"
|
||||
description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document."
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -1443,7 +1391,6 @@ test = ["pytest"]
|
||||
name = "sphinxcontrib-htmlhelp"
|
||||
version = "2.0.0"
|
||||
description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -1459,7 +1406,6 @@ test = ["html5lib", "pytest"]
|
||||
name = "sphinxcontrib-jsmath"
|
||||
version = "1.0.1"
|
||||
description = "A sphinx extension which renders display math in HTML via JavaScript"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -1474,7 +1420,6 @@ test = ["flake8", "mypy", "pytest"]
|
||||
name = "sphinxcontrib-qthelp"
|
||||
version = "1.0.3"
|
||||
description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document."
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -1490,7 +1435,6 @@ test = ["pytest"]
|
||||
name = "sphinxcontrib-serializinghtml"
|
||||
version = "1.1.5"
|
||||
description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)."
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -1504,21 +1448,24 @@ test = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "sqlparse"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
description = "A non-validating SQL parser."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "sqlparse-0.4.3-py3-none-any.whl", hash = "sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34"},
|
||||
{file = "sqlparse-0.4.3.tar.gz", hash = "sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"},
|
||||
{file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"},
|
||||
{file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["build", "flake8"]
|
||||
doc = ["sphinx"]
|
||||
test = ["pytest", "pytest-cov"]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
description = "A lil' TOML parser"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -1530,7 +1477,6 @@ files = [
|
||||
name = "traitlets"
|
||||
version = "5.8.1"
|
||||
description = "Traitlets Python configuration system"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -1546,7 +1492,6 @@ test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"]
|
||||
name = "typing-extensions"
|
||||
version = "4.4.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -1558,7 +1503,6 @@ files = [
|
||||
name = "urllib3"
|
||||
version = "1.26.13"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
files = [
|
||||
@ -1575,7 +1519,6 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
name = "wcwidth"
|
||||
version = "0.2.5"
|
||||
description = "Measures the displayed width of unicode strings in a terminal"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -1583,37 +1526,10 @@ files = [
|
||||
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xapian-bindings"
|
||||
version = "0.1.0"
|
||||
description = "Meta-package to build and install xapian-bindings extension."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "xapian-bindings-0.1.0.tar.gz", hash = "sha256:f2b0396082ebf4f6681ab43d6d8fd1f63b6964b18c32c91236ed067c6f62ad14"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xapian-haystack"
|
||||
version = "3.0.1"
|
||||
description = "A Xapian backend for Haystack"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "xapian-haystack-3.0.1.tar.gz", hash = "sha256:a5c0e1262b95008df4dfeb58d093c654acee3f2b27ea3f7d366900895cdc70f9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
django = ">=2.2"
|
||||
django-haystack = ">=2.8.0"
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.11.0"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -1626,10 +1542,10 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker
|
||||
testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
|
||||
|
||||
[extras]
|
||||
docs = ["Sphinx", "sphinx-rtd-theme", "sphinx-copybutton"]
|
||||
docs = ["Sphinx", "sphinx-copybutton", "sphinx-rtd-theme"]
|
||||
testing = ["coverage"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "95b9a07660bd8f95a5a90cc273071a675d884424479cd1ed922438dc767d230a"
|
||||
content-hash = "32bf0229e7ac812ea278a36587c184cd4ae507f87816f573447e85cd5312e52c"
|
||||
|
@ -33,10 +33,8 @@ phonenumbers = "^8.12"
|
||||
django-ajax-selects = "^2.1.0"
|
||||
reportlab = "^3.6"
|
||||
django-haystack = "^3.2.1"
|
||||
xapian-haystack = "^3.0.1"
|
||||
xapian-bindings = "^0.1.0"
|
||||
libsass = "^0.22"
|
||||
django-ordered-model = "^3.6"
|
||||
django-ordered-model = "^3.7"
|
||||
django-simple-captcha = "^0.5.17"
|
||||
python-dateutil = "^2.8.2"
|
||||
psycopg2-binary = "2.9.3"
|
||||
@ -59,6 +57,7 @@ testing = ["coverage"]
|
||||
docs = ["Sphinx", "sphinx-rtd-theme", "sphinx-copybutton"]
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
freezegun = "^1.2.2" # used to test time-dependent code
|
||||
django-debug-toolbar = "^4.0.0"
|
||||
ipython = "^7.28.0"
|
||||
black = "^23.3.0"
|
||||
|
@ -191,9 +191,9 @@ TEMPLATES = [
|
||||
|
||||
HAYSTACK_CONNECTIONS = {
|
||||
"default": {
|
||||
"ENGINE": "xapian_backend.XapianEngine",
|
||||
"PATH": os.path.join(os.path.dirname(__file__), "search_indexes", "xapian"),
|
||||
"INCLUDE_SPELLING": True,
|
||||
"ENGINE": "haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine",
|
||||
'URL': 'http://localhost:9200/',
|
||||
'INDEX_NAME': 'haystack',
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,7 +327,8 @@ SITH_CLUB_ROOT_PAGE = "clubs"
|
||||
|
||||
# Define the date in the year serving as reference for the subscriptions calendar
|
||||
# (month, day)
|
||||
SITH_START_DATE = (8, 15) # 15th August
|
||||
SITH_SEMESTER_START_AUTUMN = (8, 15) # 15 August
|
||||
SITH_SEMESTER_START_SPRING = (2, 15) # 15 February
|
||||
|
||||
# Used to determine the valid promos
|
||||
SITH_SCHOOL_START_YEAR = 1999
|
||||
@ -714,7 +715,7 @@ SITH_FRONT_DEP_VERSIONS = {
|
||||
"https://github.com/chartjs/Chart.js/": "2.6.0",
|
||||
"https://github.com/xdan/datetimepicker/": "2.5.21",
|
||||
"https://github.com/Ionaru/easy-markdown-editor/": "2.18.0",
|
||||
"https://github.com/FortAwesome/Font-Awesome/": "6.4.0",
|
||||
"https://github.com/FortAwesome/Font-Awesome/": "4.7.0",
|
||||
"https://github.com/jquery/jquery/": "3.6.2",
|
||||
"https://github.com/sethmcl/jquery-ui/": "1.11.1",
|
||||
"https://github.com/viralpatel/jquery.shorten/": "",
|
||||
|
@ -114,12 +114,12 @@ class Subscription(models.Model):
|
||||
return "No user - " + str(self.pk)
|
||||
|
||||
@staticmethod
|
||||
def compute_start(d=None, duration=1, user=None):
|
||||
def compute_start(d: date = None, duration: int = 1, user: User = None) -> date:
|
||||
"""
|
||||
This function computes the start date of the subscription with respect to the given date (default is today),
|
||||
and the start date given in settings.SITH_START_DATE.
|
||||
and the start date given in settings.SITH_SEMESTER_START_AUTUMN.
|
||||
It takes the nearest past start date.
|
||||
Exemples: with SITH_START_DATE = (8, 15)
|
||||
Exemples: with SITH_SEMESTER_START_AUTUMN = (8, 15)
|
||||
Today -> Start date
|
||||
2015-03-17 -> 2015-02-15
|
||||
2015-01-11 -> 2014-08-15
|
||||
@ -135,9 +135,9 @@ class Subscription(models.Model):
|
||||
return get_start_of_semester(d)
|
||||
|
||||
@staticmethod
|
||||
def compute_end(duration, start=None, user=None):
|
||||
def compute_end(duration: int, start: date = None, user: User = None) -> date:
|
||||
"""
|
||||
This function compute the end date of the subscription given a start date and a duration in number of semestre
|
||||
This function compute the end date of the subscription given a start date and a duration in number of semester
|
||||
Exemple:
|
||||
Start - Duration -> End date
|
||||
2015-09-18 - 1 -> 2016-03-18
|
||||
@ -153,7 +153,7 @@ class Subscription(models.Model):
|
||||
days=math.ceil((6 * duration - round(6 * duration)) * 30),
|
||||
)
|
||||
|
||||
def can_be_edited_by(self, user):
|
||||
def can_be_edited_by(self, user: User):
|
||||
return user.is_board_member or user.is_root
|
||||
|
||||
def is_valid_now(self):
|
||||
|
@ -31,7 +31,7 @@ from django.core.exceptions import ValidationError
|
||||
from datetime import timedelta, date
|
||||
|
||||
from core.models import User
|
||||
from core.utils import get_start_of_semester, get_semester
|
||||
from core.utils import get_start_of_semester, get_semester_code
|
||||
from club.models import Club
|
||||
|
||||
|
||||
@ -164,14 +164,14 @@ class TrombiUser(models.Model):
|
||||
if m.description:
|
||||
role += " (%s)" % m.description
|
||||
if m.end_date:
|
||||
end_date = get_semester(m.end_date)
|
||||
end_date = get_semester_code(m.end_date)
|
||||
else:
|
||||
end_date = ""
|
||||
TrombiClubMembership(
|
||||
user=self,
|
||||
club=str(m.club),
|
||||
role=role[:64],
|
||||
start=get_semester(m.start_date),
|
||||
start=get_semester_code(m.start_date),
|
||||
end=end_date,
|
||||
).save()
|
||||
|
||||
|
Reference in New Issue
Block a user