mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-22 14:13:21 +00:00
commit
0790ae2298
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@ -8,11 +8,7 @@ updates:
|
||||
- package-ecosystem: "pip" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "daily"
|
||||
# Raise pull requests for version updates
|
||||
# to pip against the `develop` branch
|
||||
interval: "weekly"
|
||||
target-branch: "taiste"
|
||||
reviewers:
|
||||
- "ae-utbm/developpers-v3"
|
||||
commit-message:
|
||||
prefix: "[UPDATE] "
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -17,4 +17,6 @@ sith/settings_custom.py
|
||||
sith/search_indexes/
|
||||
.coverage
|
||||
coverage_report/
|
||||
doc/_build
|
||||
|
||||
# compiled documentation
|
||||
site/
|
||||
|
@ -1,10 +1,21 @@
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.5.1
|
||||
rev: v0.5.5
|
||||
hooks:
|
||||
- id: ruff # just check the code, and print the errors
|
||||
- id: ruff # actually fix the fixable errors, but print nothing
|
||||
args: ["--fix", "--silent"]
|
||||
# Run the formatter.
|
||||
- id: ruff-format
|
||||
- id: ruff-format
|
||||
- repo: https://github.com/rtts/djhtml
|
||||
rev: 3.0.6
|
||||
hooks:
|
||||
- id: djhtml
|
||||
name: format templates
|
||||
entry: djhtml --tabwidth 2
|
||||
types: ["jinja"]
|
||||
- id: djcss
|
||||
name: format scss files
|
||||
entry: djcss --tabwidth 2
|
||||
types: ["scss"]
|
||||
|
@ -1,27 +1,27 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Accounting type list{% endtrans %}
|
||||
{% trans %}Accounting type list{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
{% trans %}Accounting types{% endtrans %}
|
||||
</p>
|
||||
<hr>
|
||||
<p><a href="{{ url('accounting:type_new') }}">{% trans %}New accounting type{% endtrans %}</a></p>
|
||||
{% if accountingtype_list %}
|
||||
<h3>{% trans %}Accounting type list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for a in accountingtype_list %}
|
||||
<li><a href="{{ url('accounting:type_edit', type_id=a.id) }}">{{ a }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}There is no types in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
{% trans %}Accounting types{% endtrans %}
|
||||
</p>
|
||||
<hr>
|
||||
<p><a href="{{ url('accounting:type_new') }}">{% trans %}New accounting type{% endtrans %}</a></p>
|
||||
{% if accountingtype_list %}
|
||||
<h3>{% trans %}Accounting type list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for a in accountingtype_list %}
|
||||
<li><a href="{{ url('accounting:type_edit', type_id=a.id) }}">{{ a }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}There is no types in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -1,37 +1,37 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Bank account: {% endtrans %}{{ object.name }}
|
||||
{% trans %}Bank account: {% endtrans %}{{ object.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
{{ object.name }}
|
||||
</p>
|
||||
<hr>
|
||||
<h2>{% trans %}Bank account: {% endtrans %}{{ object.name }}</h2>
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and not object.club_accounts.exists() %}
|
||||
<a href="{{ url('accounting:bank_delete', b_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
<h4>{% trans %}Infos{% endtrans %}</h4>
|
||||
<ul>
|
||||
<li><strong>{% trans %}IBAN: {% endtrans %}</strong>{{ object.iban }}</li>
|
||||
<li><strong>{% trans %}Number: {% endtrans %}</strong>{{ object.number }}</li>
|
||||
</ul>
|
||||
<p><a href="{{ url('accounting:club_new') }}?parent={{ object.id }}">{% trans %}New club account{% endtrans %}</a></p>
|
||||
<ul>
|
||||
{% for c in object.club_accounts.all() %}
|
||||
<li><a href="{{ url('accounting:club_details', c_account_id=c.id) }}">{{ c }}</a>
|
||||
- <a href="{{ url('accounting:club_edit', c_account_id=c.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% if c.journals.count() == 0 %}
|
||||
- <a href="{{ url('accounting:club_delete', c_account_id=c.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
{{ object.name }}
|
||||
</p>
|
||||
<hr>
|
||||
<h2>{% trans %}Bank account: {% endtrans %}{{ object.name }}</h2>
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and not object.club_accounts.exists() %}
|
||||
<a href="{{ url('accounting:bank_delete', b_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
<h4>{% trans %}Infos{% endtrans %}</h4>
|
||||
<ul>
|
||||
<li><strong>{% trans %}IBAN: {% endtrans %}</strong>{{ object.iban }}</li>
|
||||
<li><strong>{% trans %}Number: {% endtrans %}</strong>{{ object.number }}</li>
|
||||
</ul>
|
||||
<p><a href="{{ url('accounting:club_new') }}?parent={{ object.id }}">{% trans %}New club account{% endtrans %}</a></p>
|
||||
<ul>
|
||||
{% for c in object.club_accounts.all() %}
|
||||
<li><a href="{{ url('accounting:club_details', c_account_id=c.id) }}">{{ c }}</a>
|
||||
- <a href="{{ url('accounting:club_edit', c_account_id=c.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% if c.journals.count() == 0 %}
|
||||
- <a href="{{ url('accounting:club_delete', c_account_id=c.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,32 +1,32 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Bank account list{% endtrans %}
|
||||
{% trans %}Bank account list{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<h4>
|
||||
{% trans %}Accounting{% endtrans %}
|
||||
</h4>
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||
<p><a href="{{ url('accounting:simple_type_list') }}">{% trans %}Manage simplified types{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('accounting:type_list') }}">{% trans %}Manage accounting types{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('accounting:bank_new') }}">{% trans %}New bank account{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% if bankaccount_list %}
|
||||
<h3>{% trans %}Bank account list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for a in object_list %}
|
||||
<li><a href="{{ url('accounting:bank_details', b_account_id=a.id) }}">{{ a }}</a>
|
||||
- <a href="{{ url('accounting:bank_edit', b_account_id=a.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}There is no accounts in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="accounting">
|
||||
<h4>
|
||||
{% trans %}Accounting{% endtrans %}
|
||||
</h4>
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||
<p><a href="{{ url('accounting:simple_type_list') }}">{% trans %}Manage simplified types{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('accounting:type_list') }}">{% trans %}Manage accounting types{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('accounting:bank_new') }}">{% trans %}New bank account{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% if bankaccount_list %}
|
||||
<h3>{% trans %}Bank account list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for a in object_list %}
|
||||
<li><a href="{{ url('accounting:bank_details', b_account_id=a.id) }}">{{ a }}</a>
|
||||
- <a href="{{ url('accounting:bank_edit', b_account_id=a.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}There is no accounts in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,68 +1,68 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Club account:{% endtrans %} {{ object.name }}
|
||||
{% trans %}Club account:{% endtrans %} {{ object.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=object.bank_account.id) }}">{{object.bank_account }}</a> >
|
||||
{{ object }}
|
||||
</p>
|
||||
<hr>
|
||||
<h2>{% trans %}Club account:{% endtrans %} {{ object.name }}</h2>
|
||||
{% if user.is_root and not object.journals.exists() %}
|
||||
<a href="{{ url('accounting:club_delete', c_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
<p><a href="{{ url('accounting:label_list', clubaccount_id=object.id) }}">{% trans %}Label list{% endtrans %}</a></p>
|
||||
{% if not object.has_open_journal() %}
|
||||
<p><a href="{{ url('accounting:journal_new') }}?parent={{ object.id }}">{% trans %}New journal{% endtrans %}</a></p>
|
||||
{% else %}
|
||||
<p>{% trans %}You can not create new journal while you still have one opened{% endtrans %}</p>
|
||||
{% endif %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Name{% endtrans %}</td>
|
||||
<td>{% trans %}Start{% endtrans %}</td>
|
||||
<td>{% trans %}End{% endtrans %}</td>
|
||||
<td>{% trans %}Amount{% endtrans %}</td>
|
||||
<td>{% trans %}Effective amount{% endtrans %}</td>
|
||||
<td>{% trans %}Closed{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for j in object.journals.all() %}
|
||||
<tr>
|
||||
<td>{{ j.name }}</td>
|
||||
<td>{{ j.start_date }}</td>
|
||||
{% if j.end_date %}
|
||||
<td>{{ j.end_date }}</td>
|
||||
{% else %}
|
||||
<td> - </td>
|
||||
{% endif %}
|
||||
<td>{{ j.amount }} €</td>
|
||||
<td>{{ j.effective_amount }} €</td>
|
||||
{% if j.closed %}
|
||||
<td>{% trans %}Yes{% endtrans %}</td>
|
||||
{% else %}
|
||||
<td>{% trans %}No{% endtrans %}</td>
|
||||
{% endif %}
|
||||
<td> <a href="{{ url('accounting:journal_details', j_id=j.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('accounting:journal_edit', j_id=j.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and j.operations.count() == 0 %}
|
||||
<a href="{{ url('accounting:journal_delete', j_id=j.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=object.bank_account.id) }}">{{object.bank_account }}</a> >
|
||||
{{ object }}
|
||||
</p>
|
||||
<hr>
|
||||
<h2>{% trans %}Club account:{% endtrans %} {{ object.name }}</h2>
|
||||
{% if user.is_root and not object.journals.exists() %}
|
||||
<a href="{{ url('accounting:club_delete', c_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
<p><a href="{{ url('accounting:label_list', clubaccount_id=object.id) }}">{% trans %}Label list{% endtrans %}</a></p>
|
||||
{% if not object.has_open_journal() %}
|
||||
<p><a href="{{ url('accounting:journal_new') }}?parent={{ object.id }}">{% trans %}New journal{% endtrans %}</a></p>
|
||||
{% else %}
|
||||
<p>{% trans %}You can not create new journal while you still have one opened{% endtrans %}</p>
|
||||
{% endif %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Name{% endtrans %}</td>
|
||||
<td>{% trans %}Start{% endtrans %}</td>
|
||||
<td>{% trans %}End{% endtrans %}</td>
|
||||
<td>{% trans %}Amount{% endtrans %}</td>
|
||||
<td>{% trans %}Effective amount{% endtrans %}</td>
|
||||
<td>{% trans %}Closed{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for j in object.journals.all() %}
|
||||
<tr>
|
||||
<td>{{ j.name }}</td>
|
||||
<td>{{ j.start_date }}</td>
|
||||
{% if j.end_date %}
|
||||
<td>{{ j.end_date }}</td>
|
||||
{% else %}
|
||||
<td> - </td>
|
||||
{% endif %}
|
||||
<td>{{ j.amount }} €</td>
|
||||
<td>{{ j.effective_amount }} €</td>
|
||||
{% if j.closed %}
|
||||
<td>{% trans %}Yes{% endtrans %}</td>
|
||||
{% else %}
|
||||
<td>{% trans %}No{% endtrans %}</td>
|
||||
{% endif %}
|
||||
<td> <a href="{{ url('accounting:journal_details', j_id=j.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('accounting:journal_edit', j_id=j.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) and j.operations.count() == 0 %}
|
||||
<a href="{{ url('accounting:journal_delete', j_id=j.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,30 +1,30 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Company list{% endtrans %}
|
||||
{% trans %}Company list{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
{% if user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
%}
|
||||
<p><a href="{{ url('accounting:co_new') }}">{% trans %}Create new company{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
<br/>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Companies{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for o in object_list %}
|
||||
<tr>
|
||||
<td><a href="{{ url('accounting:co_edit', co_id=o.id) }}">{{ o.get_display_name() }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="accounting">
|
||||
{% if user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
%}
|
||||
<p><a href="{{ url('accounting:co_new') }}">{% trans %}Create new company{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
<br/>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Companies{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for o in object_list %}
|
||||
<tr>
|
||||
<td><a href="{{ url('accounting:co_edit', co_id=o.id) }}">{{ o.get_display_name() }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,103 +1,103 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}General journal:{% endtrans %} {{ object.name }}
|
||||
{% trans %}General journal:{% endtrans %} {{ object.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=object.club_account.bank_account.id) }}">{{object.club_account.bank_account }}</a> >
|
||||
<a href="{{ url('accounting:club_details', c_account_id=object.club_account.id) }}">{{ object.club_account }}</a> >
|
||||
{{ object.name }}
|
||||
</p>
|
||||
<hr>
|
||||
<h2>{% trans %}General journal:{% endtrans %} {{ object.name }}</h2>
|
||||
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.club_account.id }}">{% trans %}New label{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('accounting:label_list', clubaccount_id=object.club_account.id) }}">{% trans %}Label list{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('accounting:co_list') }}">{% trans %}Company list{% endtrans %}</a></p>
|
||||
<p><strong>{% trans %}Amount: {% endtrans %}</strong>{{ object.amount }} € -
|
||||
<strong>{% trans %}Effective amount: {% endtrans %}</strong>{{ object.effective_amount }} €</p>
|
||||
{% if object.closed %}
|
||||
<p>{% trans %}Journal is closed, you can not create operation{% endtrans %}</p>
|
||||
{% else %}
|
||||
<p><a href="{{ url('accounting:op_new', j_id=object.id) }}">{% trans %}New operation{% endtrans %}</a></p>
|
||||
</br>
|
||||
{% endif %}
|
||||
<div class="journal-table">
|
||||
<table>
|
||||
<thead>
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=object.club_account.bank_account.id) }}">{{object.club_account.bank_account }}</a> >
|
||||
<a href="{{ url('accounting:club_details', c_account_id=object.club_account.id) }}">{{ object.club_account }}</a> >
|
||||
{{ object.name }}
|
||||
</p>
|
||||
<hr>
|
||||
<h2>{% trans %}General journal:{% endtrans %} {{ object.name }}</h2>
|
||||
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.club_account.id }}">{% trans %}New label{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('accounting:label_list', clubaccount_id=object.club_account.id) }}">{% trans %}Label list{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('accounting:co_list') }}">{% trans %}Company list{% endtrans %}</a></p>
|
||||
<p><strong>{% trans %}Amount: {% endtrans %}</strong>{{ object.amount }} € -
|
||||
<strong>{% trans %}Effective amount: {% endtrans %}</strong>{{ object.effective_amount }} €</p>
|
||||
{% if object.closed %}
|
||||
<p>{% trans %}Journal is closed, you can not create operation{% endtrans %}</p>
|
||||
{% else %}
|
||||
<p><a href="{{ url('accounting:op_new', j_id=object.id) }}">{% trans %}New operation{% endtrans %}</a></p>
|
||||
</br>
|
||||
{% endif %}
|
||||
<div class="journal-table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Nb{% endtrans %}</td>
|
||||
<td>{% trans %}Date{% endtrans %}</td>
|
||||
<td>{% trans %}Label{% endtrans %}</td>
|
||||
<td>{% trans %}Amount{% endtrans %}</td>
|
||||
<td>{% trans %}Payment mode{% endtrans %}</td>
|
||||
<td>{% trans %}Target{% endtrans %}</td>
|
||||
<td>{% trans %}Code{% endtrans %}</td>
|
||||
<td>{% trans %}Nature{% endtrans %}</td>
|
||||
<td>{% trans %}Done{% endtrans %}</td>
|
||||
<td>{% trans %}Comment{% endtrans %}</td>
|
||||
<td>{% trans %}File{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
<td>{% trans %}PDF{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for o in object.operations.all() %}
|
||||
<tr>
|
||||
<td>{% trans %}Nb{% endtrans %}</td>
|
||||
<td>{% trans %}Date{% endtrans %}</td>
|
||||
<td>{% trans %}Label{% endtrans %}</td>
|
||||
<td>{% trans %}Amount{% endtrans %}</td>
|
||||
<td>{% trans %}Payment mode{% endtrans %}</td>
|
||||
<td>{% trans %}Target{% endtrans %}</td>
|
||||
<td>{% trans %}Code{% endtrans %}</td>
|
||||
<td>{% trans %}Nature{% endtrans %}</td>
|
||||
<td>{% trans %}Done{% endtrans %}</td>
|
||||
<td>{% trans %}Comment{% endtrans %}</td>
|
||||
<td>{% trans %}File{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
<td>{% trans %}PDF{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for o in object.operations.all() %}
|
||||
<tr>
|
||||
<td>{{ o.number }}</td>
|
||||
<td>{{ o.date }}</td>
|
||||
<td>{{ o.label or "" }}</td>
|
||||
{% if o.accounting_type.movement_type == "DEBIT" %}
|
||||
<td class="neg-amount"> {{ o.amount }} €</td>
|
||||
{% else %}
|
||||
<td class="pos-amount"> {{ o.amount }} €</td>
|
||||
{% endif %}
|
||||
<td>{{ o.get_mode_display() }}</td>
|
||||
{% if o.target_type == "OTHER" %}
|
||||
<td>{{ o.number }}</td>
|
||||
<td>{{ o.date }}</td>
|
||||
<td>{{ o.label or "" }}</td>
|
||||
{% if o.accounting_type.movement_type == "DEBIT" %}
|
||||
<td class="neg-amount"> {{ o.amount }} €</td>
|
||||
{% else %}
|
||||
<td class="pos-amount"> {{ o.amount }} €</td>
|
||||
{% endif %}
|
||||
<td>{{ o.get_mode_display() }}</td>
|
||||
{% if o.target_type == "OTHER" %}
|
||||
<td>{{ o.target_label }}</td>
|
||||
{% else %}
|
||||
{% else %}
|
||||
<td><a href="{{ o.target.get_absolute_url() }}">{{ o.target.get_display_name() }}</a></td>
|
||||
{% endif %}
|
||||
<td>{{ o.accounting_type.code }}</td>
|
||||
<td>{{ o.accounting_type.label }}</td>
|
||||
{% if o.done %}
|
||||
{% endif %}
|
||||
<td>{{ o.accounting_type.code }}</td>
|
||||
<td>{{ o.accounting_type.label }}</td>
|
||||
{% if o.done %}
|
||||
<td>{% trans %}Yes{% endtrans %}</td>
|
||||
{% else %}
|
||||
{% else %}
|
||||
<td>{% trans %}No{% endtrans %}</td>
|
||||
{% endif %}
|
||||
<td>{{ o.remark }}
|
||||
{% endif %}
|
||||
<td>{{ o.remark }}
|
||||
{% if not o.linked_operation and o.target_type == "ACCOUNT" and not o.target.has_open_journal() %}
|
||||
<p><strong>
|
||||
{% trans %}Warning: this operation has no linked operation because the targeted club account has no opened journal.{% endtrans %}
|
||||
</strong></p>
|
||||
<p><strong>
|
||||
{% trans url=o.target.get_absolute_url() %}Open a journal in <a href="{{ url }}">this club account</a>, then save this operation again to make the linked operation.{% endtrans %}
|
||||
</strong></p>
|
||||
<p><strong>
|
||||
{% trans %}Warning: this operation has no linked operation because the targeted club account has no opened journal.{% endtrans %}
|
||||
</strong></p>
|
||||
<p><strong>
|
||||
{% trans url=o.target.get_absolute_url() %}Open a journal in <a href="{{ url }}">this club account</a>, then save this operation again to make the linked operation.{% endtrans %}
|
||||
</strong></p>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if o.invoice %}
|
||||
</td>
|
||||
{% if o.invoice %}
|
||||
<td><a href="{{ url('core:download', file_id=o.invoice.id) }}">{{ o.invoice.name }}</a></td>
|
||||
{% else %}
|
||||
{% else %}
|
||||
<td>-</td>
|
||||
{% endif %}
|
||||
<td>
|
||||
{%
|
||||
if o.journal.club_account.bank_account.name not in ["AE TI", "TI"]
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
%}
|
||||
{% if not o.journal.closed %}
|
||||
<a href="{{ url('accounting:op_edit', op_id=o.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% endif %}
|
||||
<td>
|
||||
{%
|
||||
if o.journal.club_account.bank_account.name not in ["AE TI", "TI"]
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
%}
|
||||
{% if not o.journal.closed %}
|
||||
<a href="{{ url('accounting:op_edit', op_id=o.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td><a href="{{ url('accounting:op_pdf', op_id=o.id) }}">{% trans %}Generate{% endtrans %}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td><a href="{{ url('accounting:op_pdf', op_id=o.id) }}">{% trans %}Generate{% endtrans %}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,33 +1,33 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}General journal:{% endtrans %} {{ object.name }}
|
||||
{% trans %}General journal:{% endtrans %} {{ object.name }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<div id="accounting">
|
||||
<h3>{% trans %}Accounting statement: {% endtrans %} {{ object.name }}</h3>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Operation type{% endtrans %}</td>
|
||||
<td>{% trans %}Sum{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for k,v in statement.items() %}
|
||||
<tr>
|
||||
<td>{{ k }}</td>
|
||||
<td>{{ "%.2f" % v }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Operation type{% endtrans %}</td>
|
||||
<td>{% trans %}Sum{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for k,v in statement.items() %}
|
||||
<tr>
|
||||
<td>{{ k }}</td>
|
||||
<td>{{ "%.2f" % v }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
<p><strong>{% trans %}Amount: {% endtrans %}</strong>{{ "%.2f" % object.amount }} €</p>
|
||||
<p><strong>{% trans %}Effective amount: {% endtrans %}</strong>{{ "%.2f" %object.effective_amount }} €</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,57 +1,57 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}General journal:{% endtrans %} {{ object.name }}
|
||||
{% trans %}General journal:{% endtrans %} {{ object.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% macro display_tables(dict) %}
|
||||
<div id="accounting">
|
||||
<div id="accounting">
|
||||
<h6>{% trans %}Credit{% endtrans %}</h6>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Nature of operation{% endtrans %}</td>
|
||||
<td>{% trans %}Sum{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for k,v in dict['CREDIT'].items() %}
|
||||
<tr>
|
||||
<td>{{ k }}</td>
|
||||
<td>{{ "%.2f" % v }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Nature of operation{% endtrans %}</td>
|
||||
<td>{% trans %}Sum{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for k,v in dict['CREDIT'].items() %}
|
||||
<tr>
|
||||
<td>{{ k }}</td>
|
||||
<td>{{ "%.2f" % v }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% trans %}Total: {% endtrans %}{{ "%.2f" % dict['CREDIT_sum'] }}
|
||||
|
||||
<h6>{% trans %}Debit{% endtrans %}</h6>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Nature of operation{% endtrans %}</td>
|
||||
<td>{% trans %}Sum{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for k,v in dict['DEBIT'].items() %}
|
||||
<tr>
|
||||
<td>{{ k }}</td>
|
||||
<td>{{ "%.2f" % v }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Nature of operation{% endtrans %}</td>
|
||||
<td>{% trans %}Sum{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for k,v in dict['DEBIT'].items() %}
|
||||
<tr>
|
||||
<td>{{ k }}</td>
|
||||
<td>{{ "%.2f" % v }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% trans %}Total: {% endtrans %}{{ "%.2f" % dict['DEBIT_sum'] }}
|
||||
{% endmacro %}
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans %}Statement by nature: {% endtrans %} {{ object.name }}</h3>
|
||||
{% block content %}
|
||||
<h3>{% trans %}Statement by nature: {% endtrans %} {{ object.name }}</h3>
|
||||
|
||||
{% for k,v in statement.items() %}
|
||||
<h4 style="background: lightblue; padding: 4px;">{{ k }} : {{ "%.2f" % (v['CREDIT_sum'] - v['DEBIT_sum']) }}</h4>
|
||||
{% for k,v in statement.items() %}
|
||||
<h4 style="background: lightblue; padding: 4px;">{{ k }} : {{ "%.2f" % (v['CREDIT_sum'] - v['DEBIT_sum']) }}</h4>
|
||||
{{ display_tables(v) }}
|
||||
<hr>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,37 +1,37 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}General journal:{% endtrans %} {{ object.name }}
|
||||
{% trans %}General journal:{% endtrans %} {{ object.name }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<div id="accounting">
|
||||
<h3>{% trans %}Statement by person: {% endtrans %} {{ object.name }}</h3>
|
||||
|
||||
<h4>{% trans %}Credit{% endtrans %}</h4>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Target of the operation{% endtrans %}</td>
|
||||
<td>{% trans %}Sum{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for key in credit_statement.keys() %}
|
||||
<tr>
|
||||
{% if key.target_type == "OTHER" %}
|
||||
<td>{{ o.target_label }}</td>
|
||||
{% elif key %}
|
||||
<td><a href="{{ key.get_absolute_url() }}">{{ key.get_display_name() }}</a></td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
<td>{{ "%.2f" % credit_statement[key] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Target of the operation{% endtrans %}</td>
|
||||
<td>{% trans %}Sum{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for key in credit_statement.keys() %}
|
||||
<tr>
|
||||
{% if key.target_type == "OTHER" %}
|
||||
<td>{{ o.target_label }}</td>
|
||||
{% elif key %}
|
||||
<td><a href="{{ key.get_absolute_url() }}">{{ key.get_display_name() }}</a></td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
<td>{{ "%.2f" % credit_statement[key] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
@ -40,29 +40,29 @@
|
||||
<h4>{% trans %}Debit{% endtrans %}</h4>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Target of the operation{% endtrans %}</td>
|
||||
<td>{% trans %}Sum{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for key in debit_statement.keys() %}
|
||||
<tr>
|
||||
{% if key.target_type == "OTHER" %}
|
||||
<td>{{ o.target_label }}</td>
|
||||
{% elif key %}
|
||||
<td><a href="{{ key.get_absolute_url() }}">{{ key.get_display_name() }}</a></td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
<td>{{ "%.2f" % debit_statement[key] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Target of the operation{% endtrans %}</td>
|
||||
<td>{% trans %}Sum{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for key in debit_statement.keys() %}
|
||||
<tr>
|
||||
{% if key.target_type == "OTHER" %}
|
||||
<td>{{ o.target_label }}</td>
|
||||
{% elif key %}
|
||||
<td><a href="{{ key.get_absolute_url() }}">{{ key.get_display_name() }}</a></td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
<td>{{ "%.2f" % debit_statement[key] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
<p>Total : {{ "%.2f" % total_debit }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,36 +1,36 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Label list{% endtrans %}
|
||||
{% trans %}Label list{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=object.bank_account.id) }}">{{object.bank_account }}</a> >
|
||||
<a href="{{ url('accounting:club_details', c_account_id=object.id) }}">{{ object }}</a>
|
||||
</p>
|
||||
<hr>
|
||||
<p><a href="{{ url('accounting:club_details', c_account_id=object.id) }}">{% trans %}Back to club account{% endtrans %}</a></p>
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% if object.labels.all() %}
|
||||
<h3>{% trans %}Label list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for l in object.labels.all() %}
|
||||
<li><a href="{{ url('accounting:label_edit', label_id=l.id) }}">{{ l }}</a>
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=object.bank_account.id) }}">{{object.bank_account }}</a> >
|
||||
<a href="{{ url('accounting:club_details', c_account_id=object.id) }}">{{ object }}</a>
|
||||
</p>
|
||||
<hr>
|
||||
<p><a href="{{ url('accounting:club_details', c_account_id=object.id) }}">{% trans %}Back to club account{% endtrans %}</a></p>
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||
<p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% if object.labels.all() %}
|
||||
<h3>{% trans %}Label list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for l in object.labels.all() %}
|
||||
<li><a href="{{ url('accounting:label_edit', label_id=l.id) }}">{{ l }}</a>
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||
-
|
||||
<a href="{{ url('accounting:label_delete', label_id=l.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
-
|
||||
<a href="{{ url('accounting:label_delete', label_id=l.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}There is no label in this club account.{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}There is no label in this club account.{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -1,123 +1,123 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Edit operation{% endtrans %}
|
||||
{% trans %}Edit operation{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=object.club_account.bank_account.id) }}">{{object.club_account.bank_account }}</a> >
|
||||
<a href="{{ url('accounting:club_details', c_account_id=object.club_account.id) }}">{{ object.club_account }}</a> >
|
||||
<a href="{{ url('accounting:journal_details', j_id=object.id) }}">{{ object.name }}</a> >
|
||||
{% trans %}Edit operation{% endtrans %}
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=object.club_account.bank_account.id) }}">{{object.club_account.bank_account }}</a> >
|
||||
<a href="{{ url('accounting:club_details', c_account_id=object.club_account.id) }}">{{ object.club_account }}</a> >
|
||||
<a href="{{ url('accounting:journal_details', j_id=object.id) }}">{{ object.name }}</a> >
|
||||
{% trans %}Edit operation{% endtrans %}
|
||||
</p>
|
||||
<hr>
|
||||
<h2>{% trans %}Edit operation{% endtrans %}</h2>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors() }}
|
||||
{{ form.journal }}
|
||||
{{ form.target_id }}
|
||||
<p>{{ form.amount.errors }}<label for="{{ form.amount.name }}">{{ form.amount.label }}</label> {{ form.amount }}</p>
|
||||
<p>{{ form.remark.errors }}<label for="{{ form.remark.name }}">{{ form.remark.label }}</label> {{ form.remark }}</p>
|
||||
<br />
|
||||
<strong>{% trans %}Warning: if you select <em>Account</em>, the opposite operation will be created in the target account. If you don't want that, select <em>Club</em> instead of <em>Account</em>.{% endtrans %}</strong>
|
||||
<p>{{ form.target_type.errors }}<label for="{{ form.target_type.name }}">{{ form.target_type.label }}</label> {{ form.target_type }}</p>
|
||||
{{ form.user }}
|
||||
{{ form.club }}
|
||||
{{ form.club_account }}
|
||||
{{ form.company }}
|
||||
{{ form.target_label }}
|
||||
<span id="id_need_link_full"><label>{{ form.need_link.label }}</label> {{ form.need_link }}</span>
|
||||
<p>{{ form.date.errors }}<label for="{{ form.date.name }}">{{ form.date.label }}</label> {{ form.date }}</p>
|
||||
<p>{{ form.mode.errors }}<label for="{{ form.mode.name }}">{{ form.mode.label }}</label> {{ form.mode }}</p>
|
||||
<p>{{ form.cheque_number.errors }}<label for="{{ form.cheque_number.name }}">{{ form.cheque_number.label }}</label> {{
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors() }}
|
||||
{{ form.journal }}
|
||||
{{ form.target_id }}
|
||||
<p>{{ form.amount.errors }}<label for="{{ form.amount.name }}">{{ form.amount.label }}</label> {{ form.amount }}</p>
|
||||
<p>{{ form.remark.errors }}<label for="{{ form.remark.name }}">{{ form.remark.label }}</label> {{ form.remark }}</p>
|
||||
<br />
|
||||
<strong>{% trans %}Warning: if you select <em>Account</em>, the opposite operation will be created in the target account. If you don't want that, select <em>Club</em> instead of <em>Account</em>.{% endtrans %}</strong>
|
||||
<p>{{ form.target_type.errors }}<label for="{{ form.target_type.name }}">{{ form.target_type.label }}</label> {{ form.target_type }}</p>
|
||||
{{ form.user }}
|
||||
{{ form.club }}
|
||||
{{ form.club_account }}
|
||||
{{ form.company }}
|
||||
{{ form.target_label }}
|
||||
<span id="id_need_link_full"><label>{{ form.need_link.label }}</label> {{ form.need_link }}</span>
|
||||
<p>{{ form.date.errors }}<label for="{{ form.date.name }}">{{ form.date.label }}</label> {{ form.date }}</p>
|
||||
<p>{{ form.mode.errors }}<label for="{{ form.mode.name }}">{{ form.mode.label }}</label> {{ form.mode }}</p>
|
||||
<p>{{ form.cheque_number.errors }}<label for="{{ form.cheque_number.name }}">{{ form.cheque_number.label }}</label> {{
|
||||
form.cheque_number }}</p>
|
||||
<p>{{ form.invoice.errors }}<label for="{{ form.invoice.name }}">{{ form.invoice.label }}</label> {{ form.invoice }}</p>
|
||||
<p>{{ form.simpleaccounting_type.errors }}<label for="{{ form.simpleaccounting_type.name }}">{{
|
||||
form.simpleaccounting_type.label }}</label> {{ form.simpleaccounting_type }}</p>
|
||||
<p>{{ form.accounting_type.errors }}<label for="{{ form.accounting_type.name }}">{{ form.accounting_type.label }}</label> {{
|
||||
<p>{{ form.invoice.errors }}<label for="{{ form.invoice.name }}">{{ form.invoice.label }}</label> {{ form.invoice }}</p>
|
||||
<p>{{ form.simpleaccounting_type.errors }}<label for="{{ form.simpleaccounting_type.name }}">{{
|
||||
form.simpleaccounting_type.label }}</label> {{ form.simpleaccounting_type }}</p>
|
||||
<p>{{ form.accounting_type.errors }}<label for="{{ form.accounting_type.name }}">{{ form.accounting_type.label }}</label> {{
|
||||
form.accounting_type }}</p>
|
||||
<p>{{ form.label.errors }}<label for="{{ form.label.name }}">{{ form.label.label }}</label> {{ form.label }}</p>
|
||||
<p>{{ form.done.errors }}<label for="{{ form.done.name }}">{{ form.done.label }}</label> {{ form.done }}</p>
|
||||
{% if form.instance.linked_operation %}
|
||||
<p>{{ form.label.errors }}<label for="{{ form.label.name }}">{{ form.label.label }}</label> {{ form.label }}</p>
|
||||
<p>{{ form.done.errors }}<label for="{{ form.done.name }}">{{ form.done.label }}</label> {{ form.done }}</p>
|
||||
{% if form.instance.linked_operation %}
|
||||
{% set obj = form.instance.linked_operation %}
|
||||
<p><strong>{% trans %}Linked operation:{% endtrans %}</strong><br>
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=obj.journal.club_account.bank_account.id) }}">
|
||||
{{obj.journal.club_account.bank_account }}</a> >
|
||||
<a href="{{ url('accounting:club_details', c_account_id=obj.journal.club_account.id) }}">{{ obj.journal.club_account }}</a> >
|
||||
<a href="{{ url('accounting:journal_details', j_id=obj.journal.id) }}">{{ obj.journal }}</a> >
|
||||
n°{{ obj.number }}
|
||||
<a href="{{ url('accounting:bank_details', b_account_id=obj.journal.club_account.bank_account.id) }}">
|
||||
{{obj.journal.club_account.bank_account }}</a> >
|
||||
<a href="{{ url('accounting:club_details', c_account_id=obj.journal.club_account.id) }}">{{ obj.journal.club_account }}</a> >
|
||||
<a href="{{ url('accounting:journal_details', j_id=obj.journal.id) }}">{{ obj.journal }}</a> >
|
||||
n°{{ obj.number }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
{% endif %}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
<script>
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
<script>
|
||||
$( function() {
|
||||
var target_type = $('#id_target_type');
|
||||
var user = $('#id_user_wrapper');
|
||||
var club = $('#id_club_wrapper');
|
||||
var club_account = $('#id_club_account_wrapper');
|
||||
var company = $('#id_company_wrapper');
|
||||
var other = $('#id_target_label');
|
||||
var need_link = $('#id_need_link_full');
|
||||
function update_targets () {
|
||||
if (target_type.val() == "USER") {
|
||||
console.log(user);
|
||||
user.show();
|
||||
club.hide();
|
||||
club_account.hide();
|
||||
company.hide();
|
||||
other.hide();
|
||||
need_link.hide();
|
||||
} else if (target_type.val() == "ACCOUNT") {
|
||||
club_account.show();
|
||||
need_link.show();
|
||||
user.hide();
|
||||
club.hide();
|
||||
company.hide();
|
||||
other.hide();
|
||||
} else if (target_type.val() == "CLUB") {
|
||||
club.show();
|
||||
user.hide();
|
||||
club_account.hide();
|
||||
company.hide();
|
||||
other.hide();
|
||||
need_link.hide();
|
||||
} else if (target_type.val() == "COMPANY") {
|
||||
company.show();
|
||||
user.hide();
|
||||
club_account.hide();
|
||||
club.hide();
|
||||
other.hide();
|
||||
need_link.hide();
|
||||
} else if (target_type.val() == "OTHER") {
|
||||
other.show();
|
||||
user.hide();
|
||||
club.hide();
|
||||
club_account.hide();
|
||||
company.hide();
|
||||
need_link.hide();
|
||||
} else {
|
||||
company.hide();
|
||||
user.hide();
|
||||
club_account.hide();
|
||||
club.hide();
|
||||
other.hide();
|
||||
need_link.hide();
|
||||
}
|
||||
}
|
||||
update_targets();
|
||||
target_type.change(update_targets);
|
||||
} );
|
||||
</script>
|
||||
</div>
|
||||
var target_type = $('#id_target_type');
|
||||
var user = $('#id_user_wrapper');
|
||||
var club = $('#id_club_wrapper');
|
||||
var club_account = $('#id_club_account_wrapper');
|
||||
var company = $('#id_company_wrapper');
|
||||
var other = $('#id_target_label');
|
||||
var need_link = $('#id_need_link_full');
|
||||
function update_targets () {
|
||||
if (target_type.val() == "USER") {
|
||||
console.log(user);
|
||||
user.show();
|
||||
club.hide();
|
||||
club_account.hide();
|
||||
company.hide();
|
||||
other.hide();
|
||||
need_link.hide();
|
||||
} else if (target_type.val() == "ACCOUNT") {
|
||||
club_account.show();
|
||||
need_link.show();
|
||||
user.hide();
|
||||
club.hide();
|
||||
company.hide();
|
||||
other.hide();
|
||||
} else if (target_type.val() == "CLUB") {
|
||||
club.show();
|
||||
user.hide();
|
||||
club_account.hide();
|
||||
company.hide();
|
||||
other.hide();
|
||||
need_link.hide();
|
||||
} else if (target_type.val() == "COMPANY") {
|
||||
company.show();
|
||||
user.hide();
|
||||
club_account.hide();
|
||||
club.hide();
|
||||
other.hide();
|
||||
need_link.hide();
|
||||
} else if (target_type.val() == "OTHER") {
|
||||
other.show();
|
||||
user.hide();
|
||||
club.hide();
|
||||
club_account.hide();
|
||||
company.hide();
|
||||
need_link.hide();
|
||||
} else {
|
||||
company.hide();
|
||||
user.hide();
|
||||
club_account.hide();
|
||||
club.hide();
|
||||
other.hide();
|
||||
need_link.hide();
|
||||
}
|
||||
}
|
||||
update_targets();
|
||||
target_type.change(update_targets);
|
||||
} );
|
||||
</script>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Refound account{% endtrans %}
|
||||
{% trans %}Refound account{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<h3>{% trans %}Refound account{% endtrans %}</h3>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Refound{% endtrans %}" /></p>
|
||||
</form>
|
||||
</div>
|
||||
<div id="accounting">
|
||||
<h3>{% trans %}Refound account{% endtrans %}</h3>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Refound{% endtrans %}" /></p>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,27 +1,27 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Simplified type list{% endtrans %}
|
||||
{% trans %}Simplified type list{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
{% trans %}Simplified types{% endtrans %}
|
||||
</p>
|
||||
<hr>
|
||||
<p><a href="{{ url('accounting:simple_type_new') }}">{% trans %}New simplified type{% endtrans %}</a></p>
|
||||
{% if simplifiedaccountingtype_list %}
|
||||
<h3>{% trans %}Simplified type list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for a in simplifiedaccountingtype_list %}
|
||||
<li><a href="{{ url('accounting:simple_type_edit', type_id=a.id) }}">{{ a }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}There is no types in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="accounting">
|
||||
<p>
|
||||
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
|
||||
{% trans %}Simplified types{% endtrans %}
|
||||
</p>
|
||||
<hr>
|
||||
<p><a href="{{ url('accounting:simple_type_new') }}">{% trans %}New simplified type{% endtrans %}</a></p>
|
||||
{% if simplifiedaccountingtype_list %}
|
||||
<h3>{% trans %}Simplified type list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for a in simplifiedaccountingtype_list %}
|
||||
<li><a href="{{ url('accounting:simple_type_edit', type_id=a.id) }}">{{ a }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% trans %}There is no types in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -264,33 +264,26 @@ class TestOperation(TestCase):
|
||||
)
|
||||
self.assertContains(response, "Total : 5575.72", status_code=200)
|
||||
self.assertContains(response, "Total : 71.42")
|
||||
self.assertContains(
|
||||
response,
|
||||
"""
|
||||
<td><a href="/user/1/">S' Kia</a></td>
|
||||
|
||||
<td>3.00</td>""",
|
||||
content = response.content.decode()
|
||||
self.assertInHTML(
|
||||
"""<td><a href="/user/1/">S' Kia</a></td><td>3.00</td>""", content
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
"""
|
||||
<td><a href="/user/1/">S' Kia</a></td>
|
||||
|
||||
<td>823.00</td>""",
|
||||
self.assertInHTML(
|
||||
"""<td><a href="/user/1/">S' Kia</a></td><td>823.00</td>""", content
|
||||
)
|
||||
|
||||
def test_accounting_statement(self):
|
||||
response = self.client.get(
|
||||
reverse("accounting:journal_accounting_statement", args=[self.journal.id])
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
assert response.status_code == 200
|
||||
self.assertInHTML(
|
||||
"""
|
||||
<tr>
|
||||
<td>443 - Crédit - Ce code n'existe pas</td>
|
||||
<td>3.00</td>
|
||||
</tr>""",
|
||||
status_code=200,
|
||||
response.content.decode(),
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
|
@ -29,7 +29,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from club.models import Club, Mailing, MailingSubscription, Membership
|
||||
from core.models import User
|
||||
from core.views.forms import SelectDate, TzAwareDateTimeField
|
||||
from core.views.forms import SelectDate, SelectDateTime
|
||||
from counter.models import Counter
|
||||
|
||||
|
||||
@ -149,8 +149,12 @@ class MailingForm(forms.Form):
|
||||
|
||||
|
||||
class SellingsForm(forms.Form):
|
||||
begin_date = TzAwareDateTimeField(label=_("Begin date"), required=False)
|
||||
end_date = TzAwareDateTimeField(label=_("End date"), required=False)
|
||||
begin_date = forms.DateTimeField(
|
||||
label=_("Begin date"), widget=SelectDateTime, required=False
|
||||
)
|
||||
end_date = forms.DateTimeField(
|
||||
label=_("End date"), widget=SelectDateTime, required=False
|
||||
)
|
||||
|
||||
counters = forms.ModelMultipleChoiceField(
|
||||
Counter.objects.order_by("name").all(), label=_("Counter"), required=False
|
||||
|
@ -2,16 +2,16 @@
|
||||
{% from 'core/macros.jinja' import user_profile_link %}
|
||||
|
||||
{% block content %}
|
||||
<div id="club_detail">
|
||||
{% if club.logo %}
|
||||
<div class="club_logo"><img src="{{ club.logo.url }}" alt="{{ club.unix_name }}"></div>
|
||||
{% endif %}
|
||||
{% if page_revision %}
|
||||
{{ page_revision|markdown }}
|
||||
{% else %}
|
||||
<h3>{% trans %}Club{% endtrans %}</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="club_detail">
|
||||
{% if club.logo %}
|
||||
<div class="club_logo"><img src="{{ club.logo.url }}" alt="{{ club.unix_name }}"></div>
|
||||
{% endif %}
|
||||
{% if page_revision %}
|
||||
{{ page_revision|markdown }}
|
||||
{% else %}
|
||||
<h3>{% trans %}Club{% endtrans %}</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,48 +1,48 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Club list{% endtrans %}
|
||||
{% trans %}Club list{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% macro display_club(club) -%}
|
||||
|
||||
{% if club.is_active or user.is_root %}
|
||||
|
||||
<li><a href="{{ url('club:club_view', club_id=club.id) }}">{{ club.name }}</a>
|
||||
|
||||
{% if not club.is_active %}
|
||||
({% trans %}inactive{% endtrans %})
|
||||
{% endif %}
|
||||
{% if club.is_active or user.is_root %}
|
||||
|
||||
{% if club.president %} - <a href="{{ url('core:user_profile', user_id=club.president.user.id) }}">{{ club.president.user }}</a>{% endif %}
|
||||
{% if club.short_description %}<p>{{ club.short_description|markdown }}</p>{% endif %}
|
||||
|
||||
{% endif %}
|
||||
<li><a href="{{ url('club:club_view', club_id=club.id) }}">{{ club.name }}</a>
|
||||
|
||||
{%- if club.children.all()|length != 0 %}
|
||||
<ul>
|
||||
{%- for c in club.children.order_by('name') %}
|
||||
{{ display_club(c) }}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
{%- endif -%}
|
||||
</li>
|
||||
{% if not club.is_active %}
|
||||
({% trans %}inactive{% endtrans %})
|
||||
{% endif %}
|
||||
|
||||
{% if club.president %} - <a href="{{ url('core:user_profile', user_id=club.president.user.id) }}">{{ club.president.user }}</a>{% endif %}
|
||||
{% if club.short_description %}<p>{{ club.short_description|markdown }}</p>{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{%- if club.children.all()|length != 0 %}
|
||||
<ul>
|
||||
{%- for c in club.children.order_by('name') %}
|
||||
{{ display_club(c) }}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
{%- endif -%}
|
||||
</li>
|
||||
{%- endmacro %}
|
||||
|
||||
{% block content %}
|
||||
{% if user.is_root %}
|
||||
{% if user.is_root %}
|
||||
<p><a href="{{ url('club:club_new') }}">{% trans %}New club{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% if club_list %}
|
||||
{% endif %}
|
||||
{% if club_list %}
|
||||
<h3>{% trans %}Club list{% endtrans %}</h3>
|
||||
<ul>
|
||||
{%- for c in club_list.all().order_by('name') if c.parent is none %}
|
||||
{%- for c in club_list.all().order_by('name') if c.parent is none %}
|
||||
{{ display_club(c) }}
|
||||
{%- endfor %}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% else %}
|
||||
{% trans %}There is no club in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -2,81 +2,81 @@
|
||||
{% from 'core/macros.jinja' import user_profile_link, select_all_checkbox %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% trans %}Club members{% endtrans %}</h2>
|
||||
{% if members %}
|
||||
<h2>{% trans %}Club members{% endtrans %}</h2>
|
||||
{% if members %}
|
||||
<form action="{{ url('club:club_members', club_id=club.id) }}" id="users_old" method="post">
|
||||
{% csrf_token %}
|
||||
{% set users_old = dict(form.users_old | groupby("choice_label")) %}
|
||||
{% if users_old %}
|
||||
{{ select_all_checkbox("users_old") }}
|
||||
<p></p>
|
||||
{% endif %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}User{% endtrans %}</td>
|
||||
<td>{% trans %}Role{% endtrans %}</td>
|
||||
<td>{% trans %}Description{% endtrans %}</td>
|
||||
<td>{% trans %}Since{% endtrans %}</td>
|
||||
{% if users_old %}
|
||||
<td>{% trans %}Mark as old{% endtrans %}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for m in members %}
|
||||
<tr>
|
||||
<td>{{ user_profile_link(m.user) }}</td>
|
||||
<td>{{ settings.SITH_CLUB_ROLES[m.role] }}</td>
|
||||
<td>{{ m.description }}</td>
|
||||
<td>{{ m.start_date }}</td>
|
||||
{% if users_old %}
|
||||
<td>
|
||||
{% set user_old = users_old[m.user.get_display_name()] %}
|
||||
{% if user_old %}
|
||||
{{ user_old[0].tag() }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ form.users_old.errors }}
|
||||
{% if users_old %}
|
||||
<p></p>
|
||||
<input type="submit" name="submit" value="{% trans %}Mark as old{% endtrans %}">
|
||||
{% endif %}
|
||||
{% csrf_token %}
|
||||
{% set users_old = dict(form.users_old | groupby("choice_label")) %}
|
||||
{% if users_old %}
|
||||
{{ select_all_checkbox("users_old") }}
|
||||
<p></p>
|
||||
{% endif %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}User{% endtrans %}</td>
|
||||
<td>{% trans %}Role{% endtrans %}</td>
|
||||
<td>{% trans %}Description{% endtrans %}</td>
|
||||
<td>{% trans %}Since{% endtrans %}</td>
|
||||
{% if users_old %}
|
||||
<td>{% trans %}Mark as old{% endtrans %}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for m in members %}
|
||||
<tr>
|
||||
<td>{{ user_profile_link(m.user) }}</td>
|
||||
<td>{{ settings.SITH_CLUB_ROLES[m.role] }}</td>
|
||||
<td>{{ m.description }}</td>
|
||||
<td>{{ m.start_date }}</td>
|
||||
{% if users_old %}
|
||||
<td>
|
||||
{% set user_old = users_old[m.user.get_display_name()] %}
|
||||
{% if user_old %}
|
||||
{{ user_old[0].tag() }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ form.users_old.errors }}
|
||||
{% if users_old %}
|
||||
<p></p>
|
||||
<input type="submit" name="submit" value="{% trans %}Mark as old{% endtrans %}">
|
||||
{% endif %}
|
||||
</form>
|
||||
{% else %}
|
||||
{% else %}
|
||||
<p>{% trans %}There are no members in this club.{% endtrans %}</p>
|
||||
{% endif %}
|
||||
<form action="{{ url('club:club_members', club_id=club.id) }}" id="add_users" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors() }}
|
||||
<p>
|
||||
{{ form.users.errors }}
|
||||
<label for="{{ form.users.id_for_label }}">{{ form.users.label }} :</label>
|
||||
{{ form.users }}
|
||||
<span class="helptext">{{ form.users.help_text }}</span>
|
||||
</p>
|
||||
<p>
|
||||
{{ form.role.errors }}
|
||||
<label for="{{ form.role.id_for_label }}">{{ form.role.label }} :</label>
|
||||
{{ form.role }}
|
||||
</p>
|
||||
{% if form.start_date %}
|
||||
<p>
|
||||
{{ form.start_date.errors }}
|
||||
<label for="{{ form.start_date.id_for_label }}">{{ form.start_date.label }} :</label>
|
||||
{{ form.start_date }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<form action="{{ url('club:club_members', club_id=club.id) }}" id="add_users" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors() }}
|
||||
<p>
|
||||
{{ form.users.errors }}
|
||||
<label for="{{ form.users.id_for_label }}">{{ form.users.label }} :</label>
|
||||
{{ form.users }}
|
||||
<span class="helptext">{{ form.users.help_text }}</span>
|
||||
</p>
|
||||
<p>
|
||||
{{ form.role.errors }}
|
||||
<label for="{{ form.role.id_for_label }}">{{ form.role.label }} :</label>
|
||||
{{ form.role }}
|
||||
</p>
|
||||
{% if form.start_date %}
|
||||
<p>
|
||||
{{ form.start_date.errors }}
|
||||
<label for="{{ form.start_date.id_for_label }}">{{ form.start_date.label }} :</label>
|
||||
{{ form.start_date }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p>
|
||||
{{ form.description.errors }}
|
||||
<label for="{{ form.description.id_for_label }}">{{ form.description.label }} :</label>
|
||||
{{ form.description }}
|
||||
</p>
|
||||
<p><input type="submit" value="{% trans %}Add{% endtrans %}" /></p>
|
||||
</form>
|
||||
<p>
|
||||
{{ form.description.errors }}
|
||||
<label for="{{ form.description.id_for_label }}">{{ form.description.label }} :</label>
|
||||
{{ form.description }}
|
||||
</p>
|
||||
<p><input type="submit" value="{% trans %}Add{% endtrans %}" /></p>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
@ -2,27 +2,27 @@
|
||||
{% from 'core/macros.jinja' import user_profile_link %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% trans %}Club old members{% endtrans %}</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<td>{% trans %}User{% endtrans %}</td>
|
||||
<td>{% trans %}Role{% endtrans %}</td>
|
||||
<td>{% trans %}Description{% endtrans %}</td>
|
||||
<td>{% trans %}From{% endtrans %}</td>
|
||||
<td>{% trans %}To{% endtrans %}</td>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for m in club.members.exclude(end_date=None).order_by('-role', 'description', '-end_date').all() %}
|
||||
<tr>
|
||||
<td>{{ user_profile_link(m.user) }}</td>
|
||||
<td>{{ settings.SITH_CLUB_ROLES[m.role] }}</td>
|
||||
<td>{{ m.description }}</td>
|
||||
<td>{{ m.start_date }}</td>
|
||||
<td>{{ m.end_date }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>{% trans %}Club old members{% endtrans %}</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<td>{% trans %}User{% endtrans %}</td>
|
||||
<td>{% trans %}Role{% endtrans %}</td>
|
||||
<td>{% trans %}Description{% endtrans %}</td>
|
||||
<td>{% trans %}From{% endtrans %}</td>
|
||||
<td>{% trans %}To{% endtrans %}</td>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for m in club.members.exclude(end_date=None).order_by('-role', 'description', '-end_date').all() %}
|
||||
<tr>
|
||||
<td>{{ user_profile_link(m.user) }}</td>
|
||||
<td>{{ settings.SITH_CLUB_ROLES[m.role] }}</td>
|
||||
<td>{{ m.description }}</td>
|
||||
<td>{{ m.start_date }}</td>
|
||||
<td>{{ m.end_date }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -2,65 +2,65 @@
|
||||
{% from 'core/macros.jinja' import user_profile_link, paginate %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans %}Sales{% endtrans %}</h3>
|
||||
<form id="form" action="?page=1" method="post">
|
||||
<h3>{% trans %}Sales{% endtrans %}</h3>
|
||||
<form id="form" action="?page=1" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
<p><input type="submit" value="{% trans %}Show{% endtrans %}" /></p>
|
||||
<p><input type="submit" value="{% trans %}Download as cvs{% endtrans %}" formaction="{{ url('club:sellings_csv', club_id=object.id) }}"/></p>
|
||||
</form>
|
||||
<p>
|
||||
{% trans %}Quantity: {% endtrans %}{{ total_quantity }} {% trans %}units{% endtrans %}<br/>
|
||||
{% trans %}Total: {% endtrans %}{{ total }} €<br/>
|
||||
{% trans %}Benefit: {% endtrans %}{{ benefit }} €
|
||||
</p>
|
||||
<table>
|
||||
</form>
|
||||
<p>
|
||||
{% trans %}Quantity: {% endtrans %}{{ total_quantity }} {% trans %}units{% endtrans %}<br/>
|
||||
{% trans %}Total: {% endtrans %}{{ total }} €<br/>
|
||||
{% trans %}Benefit: {% endtrans %}{{ benefit }} €
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Date{% endtrans %}</td>
|
||||
<td>{% trans %}Counter{% endtrans %}</td>
|
||||
<td>{% trans %}Barman{% endtrans %}</td>
|
||||
<td>{% trans %}Customer{% endtrans %}</td>
|
||||
<td>{% trans %}Label{% endtrans %}</td>
|
||||
<td>{% trans %}Quantity{% endtrans %}</td>
|
||||
<td>{% trans %}Total{% endtrans %}</td>
|
||||
<td>{% trans %}Payment method{% endtrans %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans %}Date{% endtrans %}</td>
|
||||
<td>{% trans %}Counter{% endtrans %}</td>
|
||||
<td>{% trans %}Barman{% endtrans %}</td>
|
||||
<td>{% trans %}Customer{% endtrans %}</td>
|
||||
<td>{% trans %}Label{% endtrans %}</td>
|
||||
<td>{% trans %}Quantity{% endtrans %}</td>
|
||||
<td>{% trans %}Total{% endtrans %}</td>
|
||||
<td>{% trans %}Payment method{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for s in paginated_result %}
|
||||
{% for s in paginated_result %}
|
||||
<tr>
|
||||
<td>{{ s.date|localtime|date(DATETIME_FORMAT) }} {{ s.date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td>{{ s.counter }}</td>
|
||||
{% if s.seller %}
|
||||
<td>{{ s.date|localtime|date(DATETIME_FORMAT) }} {{ s.date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td>{{ s.counter }}</td>
|
||||
{% if s.seller %}
|
||||
<td><a href="{{ s.seller.get_absolute_url() }}">{{ s.seller.get_display_name() }}</a></td>
|
||||
{% else %}
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
{% if s.customer %}
|
||||
{% endif %}
|
||||
{% if s.customer %}
|
||||
<td><a href="{{ s.customer.user.get_absolute_url() }}">{{ s.customer.user.get_display_name() }}</a></td>
|
||||
{% else %}
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
<td>{{ s.label }}</td>
|
||||
<td>{{ s.quantity }}</td>
|
||||
<td>{{ s.quantity * s.unit_price }} €</td>
|
||||
<td>{{ s.get_payment_method_display() }}</td>
|
||||
{% if s.is_owned_by(user) %}
|
||||
<td><a href="{{ url('counter:selling_delete', selling_id=s.id) }}">{% trans %}Delete{% endtrans %}</a></td>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<td>{{ s.label }}</td>
|
||||
<td>{{ s.quantity }}</td>
|
||||
<td>{{ s.quantity * s.unit_price }} €</td>
|
||||
<td>{{ s.get_payment_method_display() }}</td>
|
||||
{% if s.is_owned_by(user) %}
|
||||
<td><a href="{{ url('counter:selling_delete', selling_id=s.id) }}">{% trans %}Delete{% endtrans %}</a></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<script type="text/javascript">
|
||||
</table>
|
||||
<script type="text/javascript">
|
||||
function formPagination(link){
|
||||
$("form").attr("action", link.href);
|
||||
link.href = "javascript:void(0)"; // block link action
|
||||
$("form").submit();
|
||||
$("form").attr("action", link.href);
|
||||
link.href = "javascript:void(0)"; // block link action
|
||||
$("form").submit();
|
||||
}
|
||||
</script>
|
||||
{{ paginate(paginated_result, paginator, "formPagination(this)") }}
|
||||
</script>
|
||||
{{ paginate(paginated_result, paginator, "formPagination(this)") }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,46 +1,46 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans %}Club tools{% endtrans %}</h3>
|
||||
<div>
|
||||
<h3>{% trans %}Club tools{% endtrans %}</h3>
|
||||
<div>
|
||||
<h4>{% trans %}Communication:{% endtrans %}</h4>
|
||||
<ul>
|
||||
<li> <a href="{{ url('com:news_new') }}?club={{ object.id }}">{% trans %}Create a news{% endtrans %}</a></li>
|
||||
<li> <a href="{{ url('com:weekmail_article') }}?club={{ object.id }}">{% trans %}Post in the Weekmail{% endtrans %}</a></li>
|
||||
{% if object.trombi %}
|
||||
<li> <a href="{{ url('com:news_new') }}?club={{ object.id }}">{% trans %}Create a news{% endtrans %}</a></li>
|
||||
<li> <a href="{{ url('com:weekmail_article') }}?club={{ object.id }}">{% trans %}Post in the Weekmail{% endtrans %}</a></li>
|
||||
{% if object.trombi %}
|
||||
<li> <a href="{{ url('trombi:detail', trombi_id=object.trombi.id) }}">{% trans %}Edit Trombi{% endtrans %}</a></li>
|
||||
{% else %}
|
||||
{% else %}
|
||||
<li> <a href="{{ url('trombi:create', club_id=object.id) }}">{% trans %}New Trombi{% endtrans %}</a></li>
|
||||
<li> <a href="{{ url('club:poster_list', club_id=object.id) }}">{% trans %}Posters{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
<h4>{% trans %}Counters:{% endtrans %}</h4>
|
||||
<ul>
|
||||
{% if object.unix_name == settings.SITH_LAUNDERETTE_MANAGER['unix_name'] %}
|
||||
{% for l in Launderette.objects.all() %}
|
||||
<li><a href="{{ url('launderette:main_click', launderette_id=l.id) }}">{{ l }}</a></li>
|
||||
{% endfor %}
|
||||
{% elif object.counters.filter(type="OFFICE")|count > 0 %}
|
||||
{% if object.unix_name == settings.SITH_LAUNDERETTE_MANAGER['unix_name'] %}
|
||||
{% for l in Launderette.objects.all() %}
|
||||
<li><a href="{{ url('launderette:main_click', launderette_id=l.id) }}">{{ l }}</a></li>
|
||||
{% endfor %}
|
||||
{% elif object.counters.filter(type="OFFICE")|count > 0 %}
|
||||
{% for c in object.counters.filter(type="OFFICE") %}
|
||||
<li>{{ c }}:
|
||||
<li>{{ c }}:
|
||||
<a href="{{ url('counter:details', counter_id=c.id) }}">View</a>
|
||||
<a href="{{ url('counter:admin', counter_id=c.id) }}">Edit</a>
|
||||
</li>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% if object.club_account.exists() %}
|
||||
<h4>{% trans %}Accounting: {% endtrans %}</h4>
|
||||
<ul>
|
||||
<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>
|
||||
<li><a href="{{ url('accounting:club_details', c_account_id=ca.id) }}">{{ ca.get_display_name() }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if object.unix_name == settings.SITH_LAUNDERETTE_MANAGER['unix_name'] %}
|
||||
<li><a href="{{ url('launderette:launderette_list') }}">{% trans %}Manage launderettes{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('launderette:launderette_list') }}">{% trans %}Manage launderettes{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -2,107 +2,107 @@
|
||||
{% from 'core/macros.jinja' import select_all_checkbox %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Mailing lists{% endtrans %}
|
||||
{% trans %}Mailing lists{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<b>{% trans %}Remember : mailing lists need to be moderated, if your new created list is not shown wait until moderation takes action{% endtrans %}</b>
|
||||
<b>{% trans %}Remember : mailing lists need to be moderated, if your new created list is not shown wait until moderation takes action{% endtrans %}</b>
|
||||
|
||||
{% if mailings_not_moderated %}
|
||||
<p>{% trans %}Mailing lists waiting for moderation{% endtrans %}</p>
|
||||
<ul>
|
||||
{% for mailing in mailings_not_moderated %}
|
||||
<li>{{ mailing.email_full }}<a href="{{ url('club:mailing_delete', mailing_id=mailing.id) }}"> - {% trans %}Delete{% endtrans %}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if mailings_not_moderated %}
|
||||
<p>{% trans %}Mailing lists waiting for moderation{% endtrans %}</p>
|
||||
<ul>
|
||||
{% for mailing in mailings_not_moderated %}
|
||||
<li>{{ mailing.email_full }}<a href="{{ url('club:mailing_delete', mailing_id=mailing.id) }}"> - {% trans %}Delete{% endtrans %}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if mailings_moderated %}
|
||||
{% if mailings_moderated %}
|
||||
{% for mailing in mailings_moderated %}
|
||||
<h2>{% trans %}Mailing{% endtrans %} {{ mailing.email_full }}
|
||||
<h2>{% trans %}Mailing{% endtrans %} {{ mailing.email_full }}
|
||||
{%- if user.is_owner(mailing) -%}
|
||||
<a href="{{ url('club:mailing_delete', mailing_id=mailing.id) }}"> - {% trans %}Delete{% endtrans %}</a>
|
||||
<a href="{{ url('club:mailing_delete', mailing_id=mailing.id) }}"> - {% trans %}Delete{% endtrans %}</a>
|
||||
{%- endif -%}
|
||||
</h2>
|
||||
<form method="GET" action="{{ url('club:mailing_generate', mailing_id=mailing.id) }}" style="display:inline-block;">
|
||||
</h2>
|
||||
<form method="GET" action="{{ url('club:mailing_generate', mailing_id=mailing.id) }}" style="display:inline-block;">
|
||||
<input type="submit" name="generateMalingList" value="{% trans %}Generate mailing list{% endtrans %}">
|
||||
</form>
|
||||
{% set form_mailing_removal = form["removal_" + mailing.id|string] %}
|
||||
{% if form_mailing_removal.field.choices %}
|
||||
{% set ms = dict(mailing.subscriptions.all() | groupby('id')) %}
|
||||
<form action="{{ url('club:mailing', club_id=club.id) }}" id="{{ form_mailing_removal.auto_id }}" method="post" enctype="multipart/form-data">
|
||||
<p style="margin-bottom: 1em;">{{ select_all_checkbox(form_mailing_removal.auto_id) }}</p>
|
||||
{% csrf_token %}
|
||||
<input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.REMOVE_SUBSCRIPTION }}" />
|
||||
<table>
|
||||
</form>
|
||||
{% set form_mailing_removal = form["removal_" + mailing.id|string] %}
|
||||
{% if form_mailing_removal.field.choices %}
|
||||
{% set ms = dict(mailing.subscriptions.all() | groupby('id')) %}
|
||||
<form action="{{ url('club:mailing', club_id=club.id) }}" id="{{ form_mailing_removal.auto_id }}" method="post" enctype="multipart/form-data">
|
||||
<p style="margin-bottom: 1em;">{{ select_all_checkbox(form_mailing_removal.auto_id) }}</p>
|
||||
{% csrf_token %}
|
||||
<input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.REMOVE_SUBSCRIPTION }}" />
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}User{% endtrans %}</td>
|
||||
<td>{% trans %}Email{% endtrans %}</td>
|
||||
<td>{% trans %}Delete{% endtrans %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans %}User{% endtrans %}</td>
|
||||
<td>{% trans %}Email{% endtrans %}</td>
|
||||
<td>{% trans %}Delete{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for widget in form_mailing_removal.subwidgets %}
|
||||
{% for widget in form_mailing_removal.subwidgets %}
|
||||
{% set user = ms[widget.data.value.value][0] %}
|
||||
<tr>
|
||||
<td>{{ user.get_username }}</td>
|
||||
<td>{{ user.get_email }}</td>
|
||||
<td>{{ widget.tag() }}</td>
|
||||
<td>{{ user.get_username }}</td>
|
||||
<td>{{ user.get_email }}</td>
|
||||
<td>{{ widget.tag() }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ form_mailing_removal.errors }}
|
||||
<p><input type="submit" value="{% trans %}Remove from mailing list{% endtrans %}" /></p>
|
||||
</form>
|
||||
</table>
|
||||
{{ form_mailing_removal.errors }}
|
||||
<p><input type="submit" value="{% trans %}Remove from mailing list{% endtrans %}" /></p>
|
||||
</form>
|
||||
|
||||
{% else %}
|
||||
{% else %}
|
||||
<p><b>{% trans %}There is no subscriber for this mailing list{% endtrans %}</b></p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% else %}
|
||||
{% else %}
|
||||
<p>{% trans %}No mailing list existing for this club{% endtrans %}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<p>{{ form.non_field_errors() }}</p>
|
||||
{% if mailings_moderated %}
|
||||
<h2>{% trans %}New member{% endtrans %}</h2>
|
||||
<form action="{{ url('club:mailing', club_id=club.id) }}" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
{{ form.subscription_mailing.errors }}
|
||||
<label for="{{ form.subscription_mailing.id_for_label }}">{{ form.subscription_mailing.label }}</label>
|
||||
{{ form.subscription_mailing }}
|
||||
</p>
|
||||
<p>
|
||||
{{ form.subscription_users.errors }}
|
||||
<label for="{{ form.subscription_users.id_for_label }}">{{ form.subscription_users.label }}</label>
|
||||
{{ form.subscription_users }}
|
||||
<span class="helptext">{{ form.subscription_users.help_text }}</span>
|
||||
</p>
|
||||
<p>
|
||||
{{ form.subscription_email.errors }}
|
||||
<label for="{{ form.subscription_email.id_for_label }}">{{ form.subscription_email.label }}</label>
|
||||
{{ form.subscription_email }}
|
||||
</p>
|
||||
<input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.NEW_SUBSCRIPTION }}" />
|
||||
<p><input type="submit" value="{% trans %}Add to mailing list{% endtrans %}" /></p>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
<h2>{% trans %}New mailing{% endtrans %}</h2>
|
||||
<p>{{ form.non_field_errors() }}</p>
|
||||
{% if mailings_moderated %}
|
||||
<h2>{% trans %}New member{% endtrans %}</h2>
|
||||
<form action="{{ url('club:mailing', club_id=club.id) }}" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
{{ form.mailing_email.errors }}
|
||||
<label for="{{ form.mailing_email.id_for_label }}">{{ form.mailing_email.label }}</label>
|
||||
{{ form.mailing_email }}
|
||||
</p>
|
||||
<input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.NEW_MALING }}" />
|
||||
<p><input type="submit" value="{% trans %}Create mailing list{% endtrans %}" /></p>
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
{{ form.subscription_mailing.errors }}
|
||||
<label for="{{ form.subscription_mailing.id_for_label }}">{{ form.subscription_mailing.label }}</label>
|
||||
{{ form.subscription_mailing }}
|
||||
</p>
|
||||
<p>
|
||||
{{ form.subscription_users.errors }}
|
||||
<label for="{{ form.subscription_users.id_for_label }}">{{ form.subscription_users.label }}</label>
|
||||
{{ form.subscription_users }}
|
||||
<span class="helptext">{{ form.subscription_users.help_text }}</span>
|
||||
</p>
|
||||
<p>
|
||||
{{ form.subscription_email.errors }}
|
||||
<label for="{{ form.subscription_email.id_for_label }}">{{ form.subscription_email.label }}</label>
|
||||
{{ form.subscription_email }}
|
||||
</p>
|
||||
<input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.NEW_SUBSCRIPTION }}" />
|
||||
<p><input type="submit" value="{% trans %}Add to mailing list{% endtrans %}" /></p>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
<h2>{% trans %}New mailing{% endtrans %}</h2>
|
||||
<form action="{{ url('club:mailing', club_id=club.id) }}" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
{{ form.mailing_email.errors }}
|
||||
<label for="{{ form.mailing_email.id_for_label }}">{{ form.mailing_email.label }}</label>
|
||||
{{ form.mailing_email }}
|
||||
</p>
|
||||
<input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.NEW_MALING }}" />
|
||||
<p><input type="submit" value="{% trans %}Create mailing list{% endtrans %}" /></p>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -2,11 +2,11 @@
|
||||
{% from 'core/macros_pages.jinja' import page_history %}
|
||||
|
||||
{% block content %}
|
||||
{% if club.page %}
|
||||
{{ page_history(club.page) }}
|
||||
{% else %}
|
||||
{% trans %}No page existing for this club{% endtrans %}
|
||||
{% endif %}
|
||||
{% if club.page %}
|
||||
{{ page_history(club.page) }}
|
||||
{% else %}
|
||||
{% trans %}No page existing for this club{% endtrans %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
{% from 'core/macros_pages.jinja' import page_edit_form %}
|
||||
|
||||
{% block content %}
|
||||
{{ page_edit_form(page, form, url('club:club_edit_page', club_id=page.club.id), csrf_token) }}
|
||||
{{ page_edit_form(page, form, url('club:club_edit_page', club_id=page.club.id), csrf_token) }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,48 +1,48 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Club stats{% endtrans %}
|
||||
{% trans %}Club stats{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if club_list %}
|
||||
{% if club_list %}
|
||||
<h3>{% trans %}Club stats{% endtrans %}</h3>
|
||||
<form action="" method="GET">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<select name="branch">
|
||||
{% for b in settings.SITH_PROFILE_DEPARTMENTS %}
|
||||
<option value="{{ b[0] }}">{{ b[0] }}</option>
|
||||
{% endfor %}
|
||||
{% for b in settings.SITH_PROFILE_DEPARTMENTS %}
|
||||
<option value="{{ b[0] }}">{{ b[0] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</p>
|
||||
<p><input type="submit" value="{% trans %}Show{% endtrans %}" /></p>
|
||||
</p>
|
||||
<p><input type="submit" value="{% trans %}Show{% endtrans %}" /></p>
|
||||
</form>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Club</td>
|
||||
<td>Member number</td>
|
||||
<td>Old member number</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Club</td>
|
||||
<td>Member number</td>
|
||||
<td>Old member number</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for c in club_list.order_by('id') %}
|
||||
{% set members = c.members.all() %}
|
||||
{% if request.GET['branch'] %}
|
||||
{% set members = c.members.all() %}
|
||||
{% if request.GET['branch'] %}
|
||||
{% set members = members.filter(user__department=request.GET['branch']) %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>{{ c.get_display_name() }}</td>
|
||||
<td>{{ members.filter(end_date=None, role__gt=settings.SITH_MAXIMUM_FREE_ROLE).count() }}</td>
|
||||
<td>{{ members.exclude(end_date=None, role__gt=settings.SITH_MAXIMUM_FREE_ROLE).count() }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>{{ c.get_display_name() }}</td>
|
||||
<td>{{ members.filter(end_date=None, role__gt=settings.SITH_MAXIMUM_FREE_ROLE).count() }}</td>
|
||||
<td>{{ members.exclude(end_date=None, role__gt=settings.SITH_MAXIMUM_FREE_ROLE).count() }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
{% else %}
|
||||
{% trans %}There is no club in this website.{% endtrans %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,43 +1,43 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Mailing lists administration{% endtrans %}
|
||||
{% trans %}Mailing lists administration{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% macro display_mailings(list) %}
|
||||
<table>
|
||||
<tr>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
<th>{% trans %}Club{%endtrans%}</th>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for mailing in list %}
|
||||
<tr>
|
||||
<td>{{ mailing.email_full }}</td>
|
||||
<td><a href="{{ url('club:mailing', club_id=mailing.club.id) }}">{{ mailing.club }}</a></td>
|
||||
<td>
|
||||
<a href="{{ url('com:mailing_delete', mailing_id=mailing.id) }}">{% trans %}Delete{% endtrans %}</a> - {% if not mailing.is_moderated %}<a href="{{ url('com:mailing_moderate', mailing_id=mailing.id) }}">{% trans %}Moderate{% endtrans %}</a>{% else %}{% trans user=mailing.moderator %}Moderated by {{ user }}{% endtrans %}{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
<th>{% trans %}Club{%endtrans%}</th>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for mailing in list %}
|
||||
<tr>
|
||||
<td>{{ mailing.email_full }}</td>
|
||||
<td><a href="{{ url('club:mailing', club_id=mailing.club.id) }}">{{ mailing.club }}</a></td>
|
||||
<td>
|
||||
<a href="{{ url('com:mailing_delete', mailing_id=mailing.id) }}">{% trans %}Delete{% endtrans %}</a> - {% if not mailing.is_moderated %}<a href="{{ url('com:mailing_moderate', mailing_id=mailing.id) }}">{% trans %}Moderate{% endtrans %}</a>{% else %}{% trans user=mailing.moderator %}Moderated by {{ user }}{% endtrans %}{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% trans %}This page lists all mailing lists{% endtrans %}</h1>
|
||||
<h1>{% trans %}This page lists all mailing lists{% endtrans %}</h1>
|
||||
|
||||
{% if has_unmoderated %}
|
||||
{% if has_unmoderated %}
|
||||
<h2>{% trans %}Not moderated mailing lists{% endtrans %}</h2>
|
||||
{{ display_mailings(unmoderated) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<h2>{% trans %}Moderated mailing lists{% endtrans %}</h2>
|
||||
{% if has_moderated %}
|
||||
{{ display_mailings(moderated) }}
|
||||
{% else %}
|
||||
<h2>{% trans %}Moderated mailing lists{% endtrans %}</h2>
|
||||
{% if has_moderated %}
|
||||
{{ display_mailings(moderated) }}
|
||||
{% else %}
|
||||
<p>{% trans %}No mailing list existing{% endtrans %}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
@ -2,317 +2,317 @@
|
||||
{% from 'core/macros.jinja' import user_profile_link %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}News admin{% endtrans %}
|
||||
{% trans %}News admin{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans %}News{% endtrans %}</h3>
|
||||
<h3>{% trans %}News{% endtrans %}</h3>
|
||||
|
||||
<p><a href="{{ url('com:news_new') }}">{% trans %}Create news{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('com:news_new') }}">{% trans %}Create news{% endtrans %}</a></p>
|
||||
|
||||
<hr />
|
||||
<h4>{% trans %}Notices{% endtrans %}</h4>
|
||||
{% set notices = object_list.filter(type="NOTICE").distinct().order_by('id') %}
|
||||
<h5>{% trans %}Displayed notices{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Moderator{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in notices.filter(is_moderated=True) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ user_profile_link(news.moderator) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h5>{% trans %}Notices to moderate{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in notices.filter(is_moderated=False) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h4>{% trans %}Notices{% endtrans %}</h4>
|
||||
{% set notices = object_list.filter(type="NOTICE").distinct().order_by('id') %}
|
||||
<h5>{% trans %}Displayed notices{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Moderator{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in notices.filter(is_moderated=True) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ user_profile_link(news.moderator) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h5>{% trans %}Notices to moderate{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in notices.filter(is_moderated=False) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
<h4>{% trans %}Weeklies{% endtrans %}</h4>
|
||||
{% set weeklies = object_list.filter(type="WEEKLY", dates__end_date__gte=timezone.now()).distinct().order_by('id') %}
|
||||
<h5>{% trans %}Displayed weeklies{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Moderator{% endtrans %}</td>
|
||||
<td>{% trans %}Dates{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in weeklies.filter(is_moderated=True) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ user_profile_link(news.moderator) }}</td>
|
||||
<td>
|
||||
<ul>
|
||||
{% for d in news.dates.all() %}
|
||||
<li>{{ d.start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ d.start_date|localtime|time(DATETIME_FORMAT) }} -
|
||||
{{ d.end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ d.end_date|localtime|time(DATETIME_FORMAT) }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h5>{% trans %}Weeklies to moderate{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Dates{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in weeklies.filter(is_moderated=False) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>
|
||||
<ul>
|
||||
{% for d in news.dates.all() %}
|
||||
<li>{{ d.start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ d.start_date|localtime|time(DATETIME_FORMAT) }} -
|
||||
{{ d.end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ d.end_date|localtime|time(DATETIME_FORMAT) }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h4>{% trans %}Weeklies{% endtrans %}</h4>
|
||||
{% set weeklies = object_list.filter(type="WEEKLY", dates__end_date__gte=timezone.now()).distinct().order_by('id') %}
|
||||
<h5>{% trans %}Displayed weeklies{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Moderator{% endtrans %}</td>
|
||||
<td>{% trans %}Dates{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in weeklies.filter(is_moderated=True) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ user_profile_link(news.moderator) }}</td>
|
||||
<td>
|
||||
<ul>
|
||||
{% for d in news.dates.all() %}
|
||||
<li>{{ d.start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ d.start_date|localtime|time(DATETIME_FORMAT) }} -
|
||||
{{ d.end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ d.end_date|localtime|time(DATETIME_FORMAT) }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h5>{% trans %}Weeklies to moderate{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Dates{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in weeklies.filter(is_moderated=False) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>
|
||||
<ul>
|
||||
{% for d in news.dates.all() %}
|
||||
<li>{{ d.start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ d.start_date|localtime|time(DATETIME_FORMAT) }} -
|
||||
{{ d.end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ d.end_date|localtime|time(DATETIME_FORMAT) }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
<h4>{% trans %}Calls{% endtrans %}</h4>
|
||||
{% set calls = object_list.filter(type="CALL", dates__end_date__gte=timezone.now()).distinct().order_by('id') %}
|
||||
<h5>{% trans %}Displayed calls{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Moderator{% endtrans %}</td>
|
||||
<td>{% trans %}Start{% endtrans %}</td>
|
||||
<td>{% trans %}End{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in calls.filter(is_moderated=True) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ user_profile_link(news.moderator) }}</td>
|
||||
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h5>{% trans %}Calls to moderate{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Start{% endtrans %}</td>
|
||||
<td>{% trans %}End{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in calls.filter(is_moderated=False) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h4>{% trans %}Calls{% endtrans %}</h4>
|
||||
{% set calls = object_list.filter(type="CALL", dates__end_date__gte=timezone.now()).distinct().order_by('id') %}
|
||||
<h5>{% trans %}Displayed calls{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Moderator{% endtrans %}</td>
|
||||
<td>{% trans %}Start{% endtrans %}</td>
|
||||
<td>{% trans %}End{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in calls.filter(is_moderated=True) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ user_profile_link(news.moderator) }}</td>
|
||||
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h5>{% trans %}Calls to moderate{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Start{% endtrans %}</td>
|
||||
<td>{% trans %}End{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in calls.filter(is_moderated=False) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
<h4>{% trans %}Events{% endtrans %}</h4>
|
||||
{% set events = object_list.filter(type="EVENT", dates__end_date__gte=timezone.now()).distinct().order_by('id') %}
|
||||
<h5>{% trans %}Displayed events{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Moderator{% endtrans %}</td>
|
||||
<td>{% trans %}Start{% endtrans %}</td>
|
||||
<td>{% trans %}End{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in events.filter(is_moderated=True) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ user_profile_link(news.moderator) }}</td>
|
||||
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h5>{% trans %}Events to moderate{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Start{% endtrans %}</td>
|
||||
<td>{% trans %}End{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in events.filter(is_moderated=False) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h4>{% trans %}Events{% endtrans %}</h4>
|
||||
{% set events = object_list.filter(type="EVENT", dates__end_date__gte=timezone.now()).distinct().order_by('id') %}
|
||||
<h5>{% trans %}Displayed events{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Moderator{% endtrans %}</td>
|
||||
<td>{% trans %}Start{% endtrans %}</td>
|
||||
<td>{% trans %}End{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in events.filter(is_moderated=True) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ user_profile_link(news.moderator) }}</td>
|
||||
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h5>{% trans %}Events to moderate{% endtrans %}</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Type{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Summary{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Start{% endtrans %}</td>
|
||||
<td>{% trans %}End{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for news in events.filter(is_moderated=False) %}
|
||||
<tr>
|
||||
<td>{{ news.get_type_display() }}</td>
|
||||
<td>{{ news.title }}</td>
|
||||
<td>{{ news.summary|markdown }}</td>
|
||||
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></td>
|
||||
<td>{{ user_profile_link(news.author) }}</td>
|
||||
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td>
|
||||
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
|
||||
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -2,48 +2,48 @@
|
||||
{% from 'core/macros.jinja' import user_profile_link, facebook_share, tweet, link_news_logo, gen_news_metatags %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}News{% endtrans %} -
|
||||
{{ object.title }}
|
||||
{% trans %}News{% endtrans %} -
|
||||
{{ object.title }}
|
||||
{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
{{ gen_news_metatags(news) }}
|
||||
{{ super() }}
|
||||
{{ gen_news_metatags(news) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p><a href="{{ url('com:news_list') }}">{% trans %}Back to news{% endtrans %}</a></p>
|
||||
<section id="news_details">
|
||||
<div class="club_logo">
|
||||
<img src="{{ link_news_logo(news)}}" alt="{{ news.club }}" />
|
||||
<a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a>
|
||||
</div>
|
||||
<h4>{{ news.title }}</h4>
|
||||
<p class="date">
|
||||
<span>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
|
||||
<span>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</p>
|
||||
<div class="news_content">
|
||||
<div><em>{{ news.summary|markdown }}</em></div>
|
||||
<br/>
|
||||
<div>{{ news.content|markdown }}</div>
|
||||
{{ facebook_share(news) }}
|
||||
{{ tweet(news) }}
|
||||
<div class="news_meta">
|
||||
<p><a href="{{ url('com:news_list') }}">{% trans %}Back to news{% endtrans %}</a></p>
|
||||
<section id="news_details">
|
||||
<div class="club_logo">
|
||||
<img src="{{ link_news_logo(news)}}" alt="{{ news.club }}" />
|
||||
<a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a>
|
||||
</div>
|
||||
<h4>{{ news.title }}</h4>
|
||||
<p class="date">
|
||||
<span>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
|
||||
<span>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</p>
|
||||
<div class="news_content">
|
||||
<div><em>{{ news.summary|markdown }}</em></div>
|
||||
<br/>
|
||||
<div>{{ news.content|markdown }}</div>
|
||||
{{ facebook_share(news) }}
|
||||
{{ tweet(news) }}
|
||||
<div class="news_meta">
|
||||
<p>{% trans %}Author: {% endtrans %}{{ user_profile_link(news.author) }}</p>
|
||||
{% if news.moderator %}
|
||||
<p>{% trans %}Moderator: {% endtrans %}{{ user_profile_link(news.moderator) }}</p>
|
||||
<p>{% trans %}Moderator: {% endtrans %}{{ user_profile_link(news.moderator) }}</p>
|
||||
{% elif user.is_com_admin %}
|
||||
<p> <a href="{{ url('com:news_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a></p>
|
||||
<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 moderated again){% 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>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -2,46 +2,46 @@
|
||||
{% from 'core/macros.jinja' import user_profile_link %}
|
||||
|
||||
{% block title %}
|
||||
{% if object %}
|
||||
{% trans %}Edit news{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}Create news{% endtrans %}
|
||||
{% endif %}
|
||||
{% if object %}
|
||||
{% trans %}Edit news{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}Create news{% endtrans %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if 'preview' in request.POST.keys() %}
|
||||
<section class="news_event">
|
||||
<h4>{{ form.instance.title }}</h4>
|
||||
<p class="date">
|
||||
{% if 'preview' in request.POST.keys() %}
|
||||
<section class="news_event">
|
||||
<h4>{{ form.instance.title }}</h4>
|
||||
<p class="date">
|
||||
<span>{{ form.instance.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ form.instance.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
|
||||
{{ form.instance.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
|
||||
<span>{{ form.instance.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ form.instance.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</p>
|
||||
<p><a href="#">{{ form.instance.club or "Club" }}</a></p>
|
||||
<div>{{ form.instance.summary|markdown }}</div>
|
||||
<div>{{ form.instance.content|markdown }}</div>
|
||||
<p>{% trans %}Author: {% endtrans %} {{ user_profile_link(form.instance.author) }}</p>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% if object %}
|
||||
<h2>{% trans %}Edit news{% endtrans %}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans %}Create news{% endtrans %}</h2>
|
||||
{% endif %}
|
||||
<form action="" method="post">
|
||||
{{ form.instance.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</p>
|
||||
<p><a href="#">{{ form.instance.club or "Club" }}</a></p>
|
||||
<div>{{ form.instance.summary|markdown }}</div>
|
||||
<div>{{ form.instance.content|markdown }}</div>
|
||||
<p>{% trans %}Author: {% endtrans %} {{ user_profile_link(form.instance.author) }}</p>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% if object %}
|
||||
<h2>{% trans %}Edit news{% endtrans %}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans %}Create news{% endtrans %}</h2>
|
||||
{% endif %}
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors() }}
|
||||
{{ form.author }}
|
||||
<p>{{ form.type.errors }}<label for="{{ form.type.name }}">{{ form.type.label }}</label>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>{% trans %}Notice: Information, election result - no date{% endtrans %}</li>
|
||||
<li>{% trans %}Event: punctual event, associated with one date{% endtrans %}</li>
|
||||
<li>{% trans %}Weekly: recurrent event, associated with many dates (specify the first one, and a deadline){% endtrans %}</li>
|
||||
<li>{% trans %}Call: long time event, associated with a long date (election appliance, ...){% endtrans %}</li>
|
||||
</ul>
|
||||
{{ form.type }}</p>
|
||||
</ul>
|
||||
{{ form.type }}</p>
|
||||
<p class="date">{{ form.start_date.errors }}<label for="{{ form.start_date.name }}">{{ form.start_date.label }}</label> {{ form.start_date }}</p>
|
||||
<p class="date">{{ form.end_date.errors }}<label for="{{ form.end_date.name }}">{{ form.end_date.label }}</label> {{ form.end_date }}</p>
|
||||
<p class="until">{{ form.until.errors }}<label for="{{ form.until.name }}">{{ form.until.label }}</label> {{ form.until }}</p>
|
||||
@ -50,38 +50,38 @@
|
||||
<p>{{ form.summary.errors }}<label for="{{ form.summary.name }}">{{ form.summary.label }}</label> {{ form.summary }}</p>
|
||||
<p>{{ form.content.errors }}<label for="{{ form.content.name }}">{{ form.content.label }}</label> {{ form.content }}</p>
|
||||
{% if user.is_com_admin %}
|
||||
<p>{{ form.automoderation.errors }}<label for="{{ form.automoderation.name }}">{{ form.automoderation.label }}</label>
|
||||
<p>{{ form.automoderation.errors }}<label for="{{ form.automoderation.name }}">{{ form.automoderation.label }}</label>
|
||||
{{ form.automoderation }}</p>
|
||||
{% endif %}
|
||||
<p><input type="submit" name="preview" value="{% trans %}Preview{% endtrans %}" /></p>
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
<script>
|
||||
$( function() {
|
||||
var type = $('input[name=type]');
|
||||
var dates = $('.date');
|
||||
var until = $('.until');
|
||||
function update_targets () {
|
||||
type_checked = $('input[name=type]:checked');
|
||||
if (type_checked.val() == "EVENT" || type_checked.val() == "CALL") {
|
||||
dates.show();
|
||||
until.hide();
|
||||
} else if (type_checked.val() == "WEEKLY") {
|
||||
dates.show();
|
||||
until.show();
|
||||
} else {
|
||||
dates.hide();
|
||||
until.hide();
|
||||
}
|
||||
{{ super() }}
|
||||
<script>
|
||||
$( function() {
|
||||
var type = $('input[name=type]');
|
||||
var dates = $('.date');
|
||||
var until = $('.until');
|
||||
function update_targets () {
|
||||
type_checked = $('input[name=type]:checked');
|
||||
if (type_checked.val() == "EVENT" || type_checked.val() == "CALL") {
|
||||
dates.show();
|
||||
until.hide();
|
||||
} else if (type_checked.val() == "WEEKLY") {
|
||||
dates.show();
|
||||
until.show();
|
||||
} else {
|
||||
dates.hide();
|
||||
until.hide();
|
||||
}
|
||||
update_targets();
|
||||
type.change(update_targets);
|
||||
} );
|
||||
</script>
|
||||
}
|
||||
update_targets();
|
||||
type.change(update_targets);
|
||||
} );
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -2,162 +2,162 @@
|
||||
{% from 'core/macros.jinja' import tweet_quick, fb_quick %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}News{% endtrans %}
|
||||
{% trans %}News{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if user.is_com_admin %}
|
||||
<div id="news_admin">
|
||||
<a class="button" href="{{ url('com:news_admin_list') }}">{% trans %}Administrate news{% endtrans %}</a>
|
||||
</div>
|
||||
<br>
|
||||
{% endif %}
|
||||
{% if user.is_com_admin %}
|
||||
<div id="news_admin">
|
||||
<a class="button" href="{{ url('com:news_admin_list') }}">{% trans %}Administrate news{% endtrans %}</a>
|
||||
</div>
|
||||
<br>
|
||||
{% endif %}
|
||||
|
||||
<div id="news">
|
||||
<div id="news">
|
||||
<div id="left_column" class="news_column">
|
||||
{% for news in object_list.filter(type="NOTICE") %}
|
||||
<section class="news_notice">
|
||||
<h4><a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a></h4>
|
||||
<div class="news_content">{{ news.summary|markdown }}</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
{% for news in object_list.filter(type="NOTICE") %}
|
||||
<section class="news_notice">
|
||||
<h4><a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a></h4>
|
||||
<div class="news_content">{{ news.summary|markdown }}</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
|
||||
{% for news in object_list.filter(dates__start_date__lte=timezone.now(), dates__end_date__gte=timezone.now(), type="CALL") %}
|
||||
<section class="news_call">
|
||||
{% for news in object_list.filter(dates__start_date__lte=timezone.now(), dates__end_date__gte=timezone.now(), type="CALL") %}
|
||||
<section class="news_call">
|
||||
<h4> <a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a></h4>
|
||||
<div class="news_date">
|
||||
<span>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
|
||||
<span>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</div>
|
||||
<div class="news_content">{{ news.summary|markdown }}</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
|
||||
{% set events_dates = NewsDate.objects.filter(end_date__gte=timezone.now(), start_date__lte=timezone.now()+timedelta(days=5), news__type="EVENT", news__is_moderated=True).datetimes('start_date', 'day') %}
|
||||
<h3>{% trans %}Events today and the next few days{% endtrans %}</h3>
|
||||
{% if events_dates %}
|
||||
{% for d in events_dates %}
|
||||
<div class="news_events_group">
|
||||
<div class="news_events_group_date">
|
||||
<div>
|
||||
<div>{{ d|localtime|date('D') }}</div>
|
||||
<div class="day">{{ d|localtime|date('d') }}</div>
|
||||
<div>{{ d|localtime|date('b') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="news_events_group_items">
|
||||
{% for news in object_list.filter(dates__start_date__gte=d,
|
||||
dates__start_date__lte=d+timedelta(days=1),
|
||||
type="EVENT").exclude(dates__end_date__lt=timezone.now())
|
||||
.order_by('dates__start_date') %}
|
||||
<section class="news_event">
|
||||
<div class="club_logo">
|
||||
{% if news.club.logo %}
|
||||
<img src="{{ news.club.logo.url }}" alt="{{ news.club }}" />
|
||||
{% else %}
|
||||
<img src="{{ static("com/img/news.png") }}" alt="{{ news.club }}" />
|
||||
{% endif %}
|
||||
</div>
|
||||
<h4> <a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a></h4>
|
||||
<div><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></div>
|
||||
<div class="news_date">
|
||||
<span>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
|
||||
<span>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
<span>{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
|
||||
<span>{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</div>
|
||||
<div class="news_content">{{ news.summary|markdown }}</div>
|
||||
</section>
|
||||
<div class="news_content">{{ news.summary|markdown }}
|
||||
<div class="button_bar">
|
||||
{{ fb_quick(news) }}
|
||||
{{ tweet_quick(news) }}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
|
||||
{% set events_dates = NewsDate.objects.filter(end_date__gte=timezone.now(), start_date__lte=timezone.now()+timedelta(days=5), news__type="EVENT", news__is_moderated=True).datetimes('start_date', 'day') %}
|
||||
<h3>{% trans %}Events today and the next few days{% endtrans %}</h3>
|
||||
{% if events_dates %}
|
||||
{% for d in events_dates %}
|
||||
<div class="news_events_group">
|
||||
<div class="news_events_group_date">
|
||||
<div>
|
||||
<div>{{ d|localtime|date('D') }}</div>
|
||||
<div class="day">{{ d|localtime|date('d') }}</div>
|
||||
<div>{{ d|localtime|date('b') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="news_events_group_items">
|
||||
{% for news in object_list.filter(dates__start_date__gte=d,
|
||||
dates__start_date__lte=d+timedelta(days=1),
|
||||
type="EVENT").exclude(dates__end_date__lt=timezone.now())
|
||||
.order_by('dates__start_date') %}
|
||||
<section class="news_event">
|
||||
<div class="club_logo">
|
||||
{% if news.club.logo %}
|
||||
<img src="{{ news.club.logo.url }}" alt="{{ news.club }}" />
|
||||
{% else %}
|
||||
<img src="{{ static("com/img/news.png") }}" alt="{{ news.club }}" />
|
||||
{% endif %}
|
||||
</div>
|
||||
<h4> <a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a></h4>
|
||||
<div><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></div>
|
||||
<div class="news_date">
|
||||
<span>{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
|
||||
<span>{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</div>
|
||||
<div class="news_content">{{ news.summary|markdown }}
|
||||
<div class="button_bar">
|
||||
{{ fb_quick(news) }}
|
||||
{{ tweet_quick(news) }}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="news_empty">
|
||||
<em>{% trans %}Nothing to come...{% endtrans %}</em>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% set coming_soon = object_list.filter(dates__start_date__gte=timezone.now()+timedelta(days=5),
|
||||
type="EVENT").order_by('dates__start_date') %}
|
||||
{% if coming_soon %}
|
||||
<h3>{% trans %}Coming soon... don't miss!{% endtrans %}</h3>
|
||||
{% for news in coming_soon %}
|
||||
<section class="news_coming_soon">
|
||||
<a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a>
|
||||
<span class="news_date">{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }} -
|
||||
{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</section>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<h3>{% trans %}All coming events{% endtrans %}</h3>
|
||||
<iframe
|
||||
src="https://embed.styledcalendar.com/#2mF2is8CEXhr4ADcX6qN"
|
||||
title="Styled Calendar"
|
||||
class="styled-calendar-container"
|
||||
style="width: 100%; border: none; height: 1060px"
|
||||
data-cy="calendar-embed-iframe">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<div id="right_column" class="news_column">
|
||||
<div id="agenda">
|
||||
<div id="agenda_title">{% trans %}Agenda{% endtrans %}</div>
|
||||
<div id="agenda_content">
|
||||
{% for d in NewsDate.objects.filter(end_date__gte=timezone.now(),
|
||||
news__is_moderated=True, news__type__in=["WEEKLY",
|
||||
"EVENT"]).order_by('start_date', 'end_date') %}
|
||||
<div class="agenda_item">
|
||||
<div class="agenda_date">
|
||||
<strong>{{ d.start_date|localtime|date('D d M Y') }}</strong>
|
||||
</div>
|
||||
<div class="agenda_time">
|
||||
<span>{{ d.start_date|localtime|time(DATETIME_FORMAT) }}</span> -
|
||||
<span>{{ d.end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong><a href="{{ url('com:news_detail', news_id=d.news.id) }}">{{ d.news.title }}</a></strong>
|
||||
<a href="{{ d.news.club.get_absolute_url() }}">{{ d.news.club }}</a>
|
||||
</div>
|
||||
<div class="agenda_item_content">{{ d.news.summary|markdown }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="news_empty">
|
||||
<em>{% trans %}Nothing to come...{% endtrans %}</em>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="birthdays">
|
||||
<div id="birthdays_title">{% trans %}Birthdays{% endtrans %}</div>
|
||||
<div id="birthdays_content">
|
||||
{% if user.is_subscribed %}
|
||||
{% set coming_soon = object_list.filter(dates__start_date__gte=timezone.now()+timedelta(days=5),
|
||||
type="EVENT").order_by('dates__start_date') %}
|
||||
{% if coming_soon %}
|
||||
<h3>{% trans %}Coming soon... don't miss!{% endtrans %}</h3>
|
||||
{% for news in coming_soon %}
|
||||
<section class="news_coming_soon">
|
||||
<a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a>
|
||||
<span class="news_date">{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }} -
|
||||
{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</section>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<h3>{% trans %}All coming events{% endtrans %}</h3>
|
||||
<iframe
|
||||
src="https://embed.styledcalendar.com/#2mF2is8CEXhr4ADcX6qN"
|
||||
title="Styled Calendar"
|
||||
class="styled-calendar-container"
|
||||
style="width: 100%; border: none; height: 1060px"
|
||||
data-cy="calendar-embed-iframe">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<div id="right_column" class="news_column">
|
||||
<div id="agenda">
|
||||
<div id="agenda_title">{% trans %}Agenda{% endtrans %}</div>
|
||||
<div id="agenda_content">
|
||||
{% for d in NewsDate.objects.filter(end_date__gte=timezone.now(),
|
||||
news__is_moderated=True, news__type__in=["WEEKLY",
|
||||
"EVENT"]).order_by('start_date', 'end_date') %}
|
||||
<div class="agenda_item">
|
||||
<div class="agenda_date">
|
||||
<strong>{{ d.start_date|localtime|date('D d M Y') }}</strong>
|
||||
</div>
|
||||
<div class="agenda_time">
|
||||
<span>{{ d.start_date|localtime|time(DATETIME_FORMAT) }}</span> -
|
||||
<span>{{ d.end_date|localtime|time(DATETIME_FORMAT) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong><a href="{{ url('com:news_detail', news_id=d.news.id) }}">{{ d.news.title }}</a></strong>
|
||||
<a href="{{ d.news.club.get_absolute_url() }}">{{ d.news.club }}</a>
|
||||
</div>
|
||||
<div class="agenda_item_content">{{ d.news.summary|markdown }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="birthdays">
|
||||
<div id="birthdays_title">{% trans %}Birthdays{% endtrans %}</div>
|
||||
<div id="birthdays_content">
|
||||
{% if user.is_subscribed %}
|
||||
{# Cache request for 1 hour #}
|
||||
{% cache 3600 "birthdays" %}
|
||||
<ul class="birthdays_year">
|
||||
{% for d in birthdays.dates('date_of_birth', 'year', 'DESC') %}
|
||||
<li>
|
||||
{% trans age=timezone.now().year - d.year %}{{ age }} year old{% endtrans %}
|
||||
<ul>
|
||||
{% for u in birthdays.filter(date_of_birth__year=d.year) %}
|
||||
<li><a href="{{ u.get_absolute_url() }}">{{ u.get_short_name() }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endcache %}
|
||||
{% else %}
|
||||
<p>{% trans %}You need an up to date subscription to access this content{% endtrans %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% cache 3600 "birthdays" %}
|
||||
<ul class="birthdays_year">
|
||||
{% for d in birthdays.dates('date_of_birth', 'year', 'DESC') %}
|
||||
<li>
|
||||
{% trans age=timezone.now().year - d.year %}{{ age }} year old{% endtrans %}
|
||||
<ul>
|
||||
{% for u in birthdays.filter(date_of_birth__year=d.year) %}
|
||||
<li><a href="{{ u.get_absolute_url() }}">{{ u.get_short_name() }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endcache %}
|
||||
{% else %}
|
||||
<p>{% trans %}You need an up to date subscription to access this content{% endtrans %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,42 +1,42 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Poster{% endtrans %}
|
||||
{% trans %}Poster{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="poster_edit">
|
||||
<div id="poster_edit">
|
||||
|
||||
<div id="title">
|
||||
<div id="links" class="left">
|
||||
{% if app == "com" %}
|
||||
<a id="list" class="link" href="{{ url(app + ":poster_list") }}">{% trans %}List{% endtrans %}</a>
|
||||
{% elif app == "club" %}
|
||||
<a id="list" class="link" href="{{ url(app + ":poster_list", club.id) }}">{% trans %}List{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<h3>{% trans %}Posters - edit{% endtrans %}</h3>
|
||||
<div id="links" class="right">
|
||||
{% if app == "com" %}
|
||||
<a class="link delete" href="{{ url(app + ":poster_delete", poster.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% elif app == "club" %}
|
||||
<a class="link delete" href="{{ url(app + ":poster_delete", club.id, poster.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="links" class="left">
|
||||
{% if app == "com" %}
|
||||
<a id="list" class="link" href="{{ url(app + ":poster_list") }}">{% trans %}List{% endtrans %}</a>
|
||||
{% elif app == "club" %}
|
||||
<a id="list" class="link" href="{{ url(app + ":poster_list", club.id) }}">{% trans %}List{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<h3>{% trans %}Posters - edit{% endtrans %}</h3>
|
||||
<div id="links" class="right">
|
||||
{% if app == "com" %}
|
||||
<a class="link delete" href="{{ url(app + ":poster_delete", poster.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% elif app == "club" %}
|
||||
<a class="link delete" href="{{ url(app + ":poster_delete", club.id, poster.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="poster">
|
||||
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,66 +1,66 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
<script src="{{ static('com/js/poster_list.js') }}"></script>
|
||||
{{ super() }}
|
||||
<script src="{{ static('com/js/poster_list.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Poster{% endtrans %}
|
||||
{% trans %}Poster{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="poster_list">
|
||||
<div id="poster_list">
|
||||
|
||||
<div id="title">
|
||||
<h3>{% trans %}Posters{% endtrans %}</h3>
|
||||
<div id="links" class="right">
|
||||
{% if app == "com" %}
|
||||
<a id="create" class="link" href="{{ url(app + ":poster_create") }}">{% trans %}Create{% endtrans %}</a>
|
||||
<a id="moderation" class="link" href="{{ url("com:poster_moderate_list") }}">{% trans %}Moderation{% endtrans %}</a>
|
||||
{% elif app == "club" %}
|
||||
<a id="create" class="link" href="{{ url(app + ":poster_create", club.id) }}">{% trans %}Create{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<h3>{% trans %}Posters{% endtrans %}</h3>
|
||||
<div id="links" class="right">
|
||||
{% if app == "com" %}
|
||||
<a id="create" class="link" href="{{ url(app + ":poster_create") }}">{% trans %}Create{% endtrans %}</a>
|
||||
<a id="moderation" class="link" href="{{ url("com:poster_moderate_list") }}">{% trans %}Moderation{% endtrans %}</a>
|
||||
{% elif app == "club" %}
|
||||
<a id="create" class="link" href="{{ url(app + ":poster_create", club.id) }}">{% trans %}Create{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="posters">
|
||||
|
||||
{% if poster_list.count() == 0 %}
|
||||
<div id="no-posters">{% trans %}No posters{% endtrans %}</div>
|
||||
{% else %}
|
||||
{% if poster_list.count() == 0 %}
|
||||
<div id="no-posters">{% trans %}No posters{% endtrans %}</div>
|
||||
{% else %}
|
||||
|
||||
{% for poster in poster_list %}
|
||||
<div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}">
|
||||
<div class="name">{{ poster.name }}</div>
|
||||
<div class="image"><img src="{{ poster.file.url }}"></img></div>
|
||||
<div class="dates">
|
||||
<div class="begin">{{ poster.date_begin | localtime | date("d/M/Y H:m") }}</div>
|
||||
<div class="end">{{ poster.date_end | localtime | date("d/M/Y H:m") }}</div>
|
||||
</div>
|
||||
{% if app == "com" %}
|
||||
<a class="edit" href="{{ url(app + ":poster_edit", poster.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% elif app == "club" %}
|
||||
<a class="edit" href="{{ url(app + ":poster_edit", club.id, poster.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% endif %}
|
||||
<div class="tooltip">
|
||||
<ul>
|
||||
{% for screen in poster.screens.all() %}
|
||||
<li>{{ screen }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for poster in poster_list %}
|
||||
<div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}">
|
||||
<div class="name">{{ poster.name }}</div>
|
||||
<div class="image"><img src="{{ poster.file.url }}"></img></div>
|
||||
<div class="dates">
|
||||
<div class="begin">{{ poster.date_begin | localtime | date("d/M/Y H:m") }}</div>
|
||||
<div class="end">{{ poster.date_end | localtime | date("d/M/Y H:m") }}</div>
|
||||
</div>
|
||||
{% if app == "com" %}
|
||||
<a class="edit" href="{{ url(app + ":poster_edit", poster.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% elif app == "club" %}
|
||||
<a class="edit" href="{{ url(app + ":poster_edit", club.id, poster.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% endif %}
|
||||
<div class="tooltip">
|
||||
<ul>
|
||||
{% for screen in poster.screens.all() %}
|
||||
<li>{{ screen }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
<div id="view"><div id="placeholder"></div></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,39 +1,39 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
<script src="{{ static('com/js/poster_list.js') }}"></script>
|
||||
{{ super() }}
|
||||
<script src="{{ static('com/js/poster_list.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="poster_list">
|
||||
<div id="poster_list">
|
||||
|
||||
<div id="title">
|
||||
<div id="links" class="left">
|
||||
<a id="list" class="link" href="{{ url("com:poster_list") }}">{% trans %}List{% endtrans %}</a>
|
||||
</div>
|
||||
<h3>{% trans %}Posters - moderation{% endtrans %}</h3>
|
||||
<div id="links" class="left">
|
||||
<a id="list" class="link" href="{{ url("com:poster_list") }}">{% trans %}List{% endtrans %}</a>
|
||||
</div>
|
||||
<h3>{% trans %}Posters - moderation{% endtrans %}</h3>
|
||||
</div>
|
||||
|
||||
<div id="posters">
|
||||
|
||||
{% if object_list.count == 0 %}
|
||||
<div id="no-posters">{% trans %}No objects{% endtrans %}</div>
|
||||
{% else %}
|
||||
{% if object_list.count == 0 %}
|
||||
<div id="no-posters">{% trans %}No objects{% endtrans %}</div>
|
||||
{% else %}
|
||||
|
||||
{% for poster in object_list %}
|
||||
<div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}">
|
||||
<div class="name"> {{ poster.name }} </div>
|
||||
<div class="image"> <img src="{{ poster.file.url }}"></img> </div>
|
||||
<a class="moderate" href="{{ url("com:poster_moderate", object_id=poster.id) }}">Moderate</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for poster in object_list %}
|
||||
<div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}">
|
||||
<div class="name"> {{ poster.name }} </div>
|
||||
<div class="image"> <img src="{{ poster.file.url }}"></img> </div>
|
||||
<a class="moderate" href="{{ url("com:poster_moderate", object_id=poster.id) }}">Moderate</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
<div id="view"><div id="placeholder"></div></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,33 +1,33 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Screen{% endtrans %}
|
||||
{% trans %}Screen{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="screen_edit">
|
||||
<div id="screen_edit">
|
||||
|
||||
<div id="title">
|
||||
<div id="links" class="left">
|
||||
<a id="list" class="link" href="{{ url("com:screen_list") }}">{% trans %}List{% endtrans %}</a>
|
||||
</div>
|
||||
<h3>{% trans %}Screen - edit{% endtrans %}</h3>
|
||||
<div id="links" class="right">
|
||||
<a class="link delete" href="{{ url("com:screen_delete", screen.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</div>
|
||||
<div id="links" class="left">
|
||||
<a id="list" class="link" href="{{ url("com:screen_list") }}">{% trans %}List{% endtrans %}</a>
|
||||
</div>
|
||||
<h3>{% trans %}Screen - edit{% endtrans %}</h3>
|
||||
<div id="links" class="right">
|
||||
<a class="link delete" href="{{ url("com:screen_delete", screen.id) }}">{% trans %}Delete{% endtrans %}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="screen">
|
||||
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,38 +1,38 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Screens{% endtrans %}
|
||||
{% trans %}Screens{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="screen_list">
|
||||
<div id="screen_list">
|
||||
|
||||
<div id="title">
|
||||
<h3>{% trans %}Screens{% endtrans %}</h3>
|
||||
<div id="links" class="right">
|
||||
<a id="create" class="link" href="{{ url("com:screen_create") }}">{% trans %}Create{% endtrans %}</a>
|
||||
</div>
|
||||
<h3>{% trans %}Screens{% endtrans %}</h3>
|
||||
<div id="links" class="right">
|
||||
<a id="create" class="link" href="{{ url("com:screen_create") }}">{% trans %}Create{% endtrans %}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="screens">
|
||||
|
||||
{% if screen_list.count() == 0 %}
|
||||
<div id="no-screens">{% trans %}No screens{% endtrans %}</div>
|
||||
{% else %}
|
||||
{% if screen_list.count() == 0 %}
|
||||
<div id="no-screens">{% trans %}No screens{% endtrans %}</div>
|
||||
{% else %}
|
||||
|
||||
{% for screen in screen_list %}
|
||||
<div class="screen">
|
||||
<div class="name">{{ screen.name }}</div>
|
||||
<a class="edit" href="{{ url("com:screen_edit", screen.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a class="slideshow" href="{{ url("com:screen_slideshow", screen.id) }}" target="_blank">{% trans %}Slideshow{% endtrans %}</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for screen in screen_list %}
|
||||
<div class="screen">
|
||||
<div class="name">{{ screen.name }}</div>
|
||||
<a class="edit" href="{{ url("com:screen_edit", screen.id) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a class="slideshow" href="{{ url("com:screen_slideshow", screen.id) }}" target="_blank">{% trans %}Slideshow{% endtrans %}</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,30 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<head>
|
||||
<title>{% trans %}Slideshow{% endtrans %}</title>
|
||||
<link href="{{ scss('com/slideshow.scss') }}" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
</head>
|
||||
<body>
|
||||
<div id="slideshow">
|
||||
|
||||
<div id="slides">
|
||||
<div id="slides">
|
||||
{% for poster in posters %}
|
||||
<div class="slide {% if loop.first %}center{% else %}right{% endif %}" display_time="{{ poster.display_time }}">
|
||||
<img src="{{ poster.file.url }}"></img>
|
||||
</div>
|
||||
<div class="slide {% if loop.first %}center{% else %}right{% endif %}" display_time="{{ poster.display_time }}">
|
||||
<img src="{{ poster.file.url }}"></img>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="progress_bullets">
|
||||
<div id="progress_bullets">
|
||||
{% for poster in posters %}
|
||||
<div class="bullet {% if loop.first %}active{% endif %}"></div>
|
||||
<div class="bullet {% if loop.first %}active{% endif %}"></div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="progress_bar"></div>
|
||||
<div id="progress_bar"></div>
|
||||
|
||||
</div>
|
||||
<script src="{{ static('core/js/jquery-3.6.2.min.js') }}"></script>
|
||||
<script src="{{ static('com/js/slideshow.js') }}"></script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -2,77 +2,77 @@
|
||||
{% from 'core/macros.jinja' import user_profile_link %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Weekmail{% endtrans %}
|
||||
{% trans %}Weekmail{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans %}Weekmail{% endtrans %} {{ object.id }}</h3>
|
||||
<p><a href="{{ url('com:weekmail_preview') }}">{% trans %}Preview{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('com:weekmail_preview') }}?send=true">{% trans %}Send{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('com:weekmail_article') }}">{% trans %}New article{% endtrans %}</a></p>
|
||||
<h4>{% trans %}Articles in no weekmail yet{% endtrans %}</h4>
|
||||
<table>
|
||||
<h3>{% trans %}Weekmail{% endtrans %} {{ object.id }}</h3>
|
||||
<p><a href="{{ url('com:weekmail_preview') }}">{% trans %}Preview{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('com:weekmail_preview') }}?send=true">{% trans %}Send{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('com:weekmail_article') }}">{% trans %}New article{% endtrans %}</a></p>
|
||||
<h4>{% trans %}Articles in no weekmail yet{% endtrans %}</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Content{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Content{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for a in orphans.all() %}
|
||||
{% for a in orphans.all() %}
|
||||
<tr>
|
||||
<td>{{ user_profile_link(a.author) }}</td>
|
||||
<td><a href="{{ a.club.get_absolute_url() }}">{{ a.club }}</a></td>
|
||||
<td>{{ a.title }}</td>
|
||||
<td>{{ a.content|markdown }}</td>
|
||||
<td>
|
||||
<a href="{{ url('com:weekmail_article_edit', article_id=a.id) }}">{% trans %}Edit{% endtrans %}</a> |
|
||||
<a href="{{ url('com:weekmail_article_delete', article_id=a.id) }}">{% trans %}Delete{% endtrans %}</a> |
|
||||
<a href="?add_article={{ a.id }}">{% trans %}Add to weekmail{% endtrans %}</a> |
|
||||
<a href="?up_article={{ a.id }}">{% trans %}Up{% endtrans %}</a> |
|
||||
<a href="?down_article={{ a.id }}">{% trans %}Down{% endtrans %}</a>
|
||||
</td>
|
||||
<td>{{ user_profile_link(a.author) }}</td>
|
||||
<td><a href="{{ a.club.get_absolute_url() }}">{{ a.club }}</a></td>
|
||||
<td>{{ a.title }}</td>
|
||||
<td>{{ a.content|markdown }}</td>
|
||||
<td>
|
||||
<a href="{{ url('com:weekmail_article_edit', article_id=a.id) }}">{% trans %}Edit{% endtrans %}</a> |
|
||||
<a href="{{ url('com:weekmail_article_delete', article_id=a.id) }}">{% trans %}Delete{% endtrans %}</a> |
|
||||
<a href="?add_article={{ a.id }}">{% trans %}Add to weekmail{% endtrans %}</a> |
|
||||
<a href="?up_article={{ a.id }}">{% trans %}Up{% endtrans %}</a> |
|
||||
<a href="?down_article={{ a.id }}">{% trans %}Down{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h4>{% trans %}Articles included the next weekmail{% endtrans %}</h4>
|
||||
<table>
|
||||
</table>
|
||||
<h4>{% trans %}Articles included the next weekmail{% endtrans %}</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Content{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans %}Author{% endtrans %}</td>
|
||||
<td>{% trans %}Club{% endtrans %}</td>
|
||||
<td>{% trans %}Title{% endtrans %}</td>
|
||||
<td>{% trans %}Content{% endtrans %}</td>
|
||||
<td>{% trans %}Actions{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for a in object.articles.order_by('rank') %}
|
||||
{% for a in object.articles.order_by('rank') %}
|
||||
<tr>
|
||||
<td>{{ user_profile_link(a.author) }}</td>
|
||||
<td><a href="{{ a.club.get_absolute_url() }}">{{ a.club }}</a></td>
|
||||
<td>{{ a.title }}</td>
|
||||
<td>{{ a.content|markdown }}</td>
|
||||
<td>
|
||||
<a href="{{ url('com:weekmail_article_edit', article_id=a.id) }}">{% trans %}Edit{% endtrans %}</a> |
|
||||
<a href="{{ url('com:weekmail_article_delete', article_id=a.id) }}">{% trans %}Delete{% endtrans %}</a> |
|
||||
<a href="?del_article={{ a.id }}">{% trans %}Delete from weekmail{% endtrans %}</a> |
|
||||
<a href="?up_article={{ a.id }}">{% trans %}Up{% endtrans %}</a> |
|
||||
<a href="?down_article={{ a.id }}">{% trans %}Down{% endtrans %}</a>
|
||||
</td>
|
||||
<td>{{ user_profile_link(a.author) }}</td>
|
||||
<td><a href="{{ a.club.get_absolute_url() }}">{{ a.club }}</a></td>
|
||||
<td>{{ a.title }}</td>
|
||||
<td>{{ a.content|markdown }}</td>
|
||||
<td>
|
||||
<a href="{{ url('com:weekmail_article_edit', article_id=a.id) }}">{% trans %}Edit{% endtrans %}</a> |
|
||||
<a href="{{ url('com:weekmail_article_delete', article_id=a.id) }}">{% trans %}Delete{% endtrans %}</a> |
|
||||
<a href="?del_article={{ a.id }}">{% trans %}Delete from weekmail{% endtrans %}</a> |
|
||||
<a href="?up_article={{ a.id }}">{% trans %}Up{% endtrans %}</a> |
|
||||
<a href="?down_article={{ a.id }}">{% trans %}Down{% endtrans %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
</table>
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -2,41 +2,41 @@
|
||||
{% from 'core/macros.jinja' import user_profile_link %}
|
||||
|
||||
{% block title %}
|
||||
{{ weekmail.title }}
|
||||
{{ weekmail.title }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<a href="{{ url('com:weekmail') }}">{% trans %}Back{% endtrans %}</a>
|
||||
{% if bad_recipients %}
|
||||
<a href="{{ url('com:weekmail') }}">{% trans %}Back{% endtrans %}</a>
|
||||
{% if bad_recipients %}
|
||||
<p>
|
||||
<span class="important">
|
||||
<span class="important">
|
||||
{% trans %}The following recipients were refused by the SMTP:{% endtrans %}
|
||||
</span>
|
||||
<ul>
|
||||
{% for r in bad_recipients.keys() %}
|
||||
<li>{{ r }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</span>
|
||||
<ul>
|
||||
{% for r in bad_recipients.keys() %}
|
||||
<li>{{ r }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<form method="post" action="">
|
||||
{% csrf_token %}
|
||||
<button type="submit" name="send" value="clean">{% trans %}Clean subscribers{% endtrans %}</button>
|
||||
{% csrf_token %}
|
||||
<button type="submit" name="send" value="clean">{% trans %}Clean subscribers{% endtrans %}</button>
|
||||
</form>
|
||||
{% else %}
|
||||
{% else %}
|
||||
{% if request.GET['send'] %}
|
||||
<p>{% trans %}Are you sure you want to send this weekmail?{% endtrans %}</p>
|
||||
{% if request.LANGUAGE_CODE != settings.LANGUAGE_CODE[:2] %}
|
||||
<p><strong>{% trans %}Warning: you are sending the weekmail in another language than the default one!{% endtrans %}</strong></p>
|
||||
{% endif %}
|
||||
<form method="post" action="">
|
||||
{% csrf_token %}
|
||||
<button type="submit" name="send" value="validate">{% trans %}Send{% endtrans %}</button>
|
||||
</form>
|
||||
<p>{% trans %}Are you sure you want to send this weekmail?{% endtrans %}</p>
|
||||
{% if request.LANGUAGE_CODE != settings.LANGUAGE_CODE[:2] %}
|
||||
<p><strong>{% trans %}Warning: you are sending the weekmail in another language than the default one!{% endtrans %}</strong></p>
|
||||
{% endif %}
|
||||
<form method="post" action="">
|
||||
{% csrf_token %}
|
||||
<button type="submit" name="send" value="validate">{% trans %}Send{% endtrans %}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<hr>
|
||||
{{ weekmail_rendered|safe }}
|
||||
{% endif %}
|
||||
<hr>
|
||||
{{ weekmail_rendered|safe }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,52 +1,52 @@
|
||||
<style type="text/css" media="all">
|
||||
h1, h2, h3, h4, h5, h6, p {
|
||||
h1, h2, h3, h4, h5, h6, p {
|
||||
padding: 5px ;
|
||||
margin: 5px;
|
||||
}
|
||||
img {
|
||||
}
|
||||
img {
|
||||
margin: 5px ;
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div style="background: #CBD1DD; padding: 0px 5%;">
|
||||
<div style="background: #F9FAFB;">
|
||||
<h2 style="background: #000; color: #f9fafb">{{ weekmail.title }}</h2>
|
||||
<img src="{{ weekmail.get_banner() }}"
|
||||
id="OWATemporaryImageDivContainerBannerForOutlook"
|
||||
>
|
||||
{% if weekmail.intro %}
|
||||
<h3 style="background: #000; color: #f9fafb">{% trans %}Intro{% endtrans %}</h3>
|
||||
{{ weekmail.intro|markdown }}
|
||||
{% endif %}
|
||||
<div style="background: #F9FAFB;">
|
||||
<h2 style="background: #000; color: #f9fafb">{{ weekmail.title }}</h2>
|
||||
<img src="{{ weekmail.get_banner() }}"
|
||||
id="OWATemporaryImageDivContainerBannerForOutlook"
|
||||
>
|
||||
{% if weekmail.intro %}
|
||||
<h3 style="background: #000; color: #f9fafb">{% trans %}Intro{% endtrans %}</h3>
|
||||
{{ weekmail.intro|markdown }}
|
||||
{% endif %}
|
||||
|
||||
<h3 style="background: #000; color: #f9fafb">{% trans %}Table of content{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for a in weekmail.articles.all() %}
|
||||
<li>[{{ a.club }}] {{ a.title }}</li>
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
<h3 style="background: #000; color: #f9fafb">{% trans %}Table of content{% endtrans %}</h3>
|
||||
<ul>
|
||||
{% for a in weekmail.articles.all() %}
|
||||
<li>[{{ a.club }}] {{ a.title }}</li>
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
|
||||
{%- for a in weekmail.articles.all() %}
|
||||
<h3 style="background: #000; color: #f9fafb">[{{ a.club }}] {{ a.title }}</h3>
|
||||
{{ a.content|markdown }}
|
||||
{%- endfor -%}
|
||||
{%- for a in weekmail.articles.all() %}
|
||||
<h3 style="background: #000; color: #f9fafb">[{{ a.club }}] {{ a.title }}</h3>
|
||||
{{ a.content|markdown }}
|
||||
{%- endfor -%}
|
||||
|
||||
{%- if weekmail.joke %}
|
||||
<h3 style="background: #000; color: #f9fafb">{% trans %}Joke{% endtrans %}</h3>
|
||||
{{ weekmail.joke|markdown }}
|
||||
{% endif -%}
|
||||
{%- if weekmail.joke %}
|
||||
<h3 style="background: #000; color: #f9fafb">{% trans %}Joke{% endtrans %}</h3>
|
||||
{{ weekmail.joke|markdown }}
|
||||
{% endif -%}
|
||||
|
||||
{%- if weekmail.protip %}
|
||||
<h3 style="background: #000; color: #f9fafb">{% trans %}Pro tip{% endtrans %}</h3>
|
||||
{{ weekmail.protip|markdown }}
|
||||
{% endif -%}
|
||||
{%- if weekmail.protip %}
|
||||
<h3 style="background: #000; color: #f9fafb">{% trans %}Pro tip{% endtrans %}</h3>
|
||||
{{ weekmail.protip|markdown }}
|
||||
{% endif -%}
|
||||
|
||||
{%- if weekmail.conclusion %}
|
||||
<h3 style="background: #000; color: #f9fafb">{% trans %}Final word{% endtrans %}</h3>
|
||||
{{ weekmail.conclusion|markdown }}
|
||||
{% endif -%}
|
||||
<img src="{{ weekmail.get_footer() }}"
|
||||
</div>
|
||||
{%- if weekmail.conclusion %}
|
||||
<h3 style="background: #000; color: #f9fafb">{% trans %}Final word{% endtrans %}</h3>
|
||||
{{ weekmail.conclusion|markdown }}
|
||||
{% endif -%}
|
||||
<img src="{{ weekmail.get_footer() }}"
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# {{ weekmail.title }}
|
||||
|
||||
{%- if weekmail.intro %}
|
||||
## {% trans %}Intro{% endtrans %}
|
||||
{{ weekmail.intro }}
|
||||
## {% trans %}Intro{% endtrans %}
|
||||
{{ weekmail.intro }}
|
||||
{% endif %}
|
||||
|
||||
## {% trans %}Table of content{% endtrans %}
|
||||
@ -11,22 +11,22 @@
|
||||
{% endfor -%}
|
||||
|
||||
{% for a in weekmail.articles.all() %}
|
||||
## [{{ a.club }}] {{ a.title }}
|
||||
{{ a.content }}
|
||||
## [{{ a.club }}] {{ a.title }}
|
||||
{{ a.content }}
|
||||
{% endfor -%}
|
||||
|
||||
{%- if weekmail.joke %}
|
||||
## {% trans %}Joke{% endtrans %}
|
||||
{{ weekmail.joke }}
|
||||
## {% trans %}Joke{% endtrans %}
|
||||
{{ weekmail.joke }}
|
||||
{% endif -%}
|
||||
|
||||
{%- if weekmail.protip %}
|
||||
## {% trans %}Pro tip{% endtrans %}
|
||||
{{ weekmail.protip }}
|
||||
## {% trans %}Pro tip{% endtrans %}
|
||||
{{ weekmail.protip }}
|
||||
{% endif -%}
|
||||
|
||||
{%- if weekmail.conclusion %}
|
||||
## {% trans %}Final word{% endtrans %}
|
||||
{{ weekmail.conclusion }}
|
||||
## {% trans %}Final word{% endtrans %}
|
||||
{{ weekmail.conclusion }}
|
||||
{% endif -%}
|
||||
|
||||
|
20
com/tests.py
20
com/tests.py
@ -69,11 +69,11 @@ class TestCom(TestCase):
|
||||
},
|
||||
)
|
||||
r = self.client.get(reverse("core:index"))
|
||||
self.assertContains(
|
||||
r,
|
||||
"""<div id="alert_box">
|
||||
<div class="markdown"><h3>ALERTE!</h3>
|
||||
<p><strong>Caaaataaaapuuuulte!!!!</strong></p>""",
|
||||
assert r.status_code == 200
|
||||
self.assertInHTML(
|
||||
"""<div id="alert_box"><div class="markdown"><h3>ALERTE!</h3>
|
||||
<p><strong>Caaaataaaapuuuulte!!!!</strong></p>""",
|
||||
r.content.decode(),
|
||||
)
|
||||
|
||||
def test_info_msg(self):
|
||||
@ -86,10 +86,12 @@ class TestCom(TestCase):
|
||||
},
|
||||
)
|
||||
r = self.client.get(reverse("core:index"))
|
||||
self.assertContains(
|
||||
r,
|
||||
"""<div id="info_box">
|
||||
<div class="markdown"><h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>""",
|
||||
|
||||
assert r.status_code == 200
|
||||
self.assertInHTML(
|
||||
"""<div id="info_box"><div class="markdown">
|
||||
<h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>""",
|
||||
r.content.decode(),
|
||||
)
|
||||
|
||||
def test_birthday_non_subscribed_user(self):
|
||||
|
21
com/views.py
21
com/views.py
@ -50,7 +50,7 @@ from core.views import (
|
||||
QuickNotifMixin,
|
||||
TabedViewMixin,
|
||||
)
|
||||
from core.views.forms import MarkdownInput, TzAwareDateTimeField
|
||||
from core.views.forms import MarkdownInput, SelectDateTime
|
||||
|
||||
# Sith object
|
||||
|
||||
@ -72,12 +72,15 @@ class PosterForm(forms.ModelForm):
|
||||
widgets = {"screens": forms.CheckboxSelectMultiple}
|
||||
help_texts = {"file": _("Format: 16:9 | Resolution: 1920x1080")}
|
||||
|
||||
date_begin = TzAwareDateTimeField(
|
||||
date_begin = forms.DateTimeField(
|
||||
label=_("Start date"),
|
||||
widget=SelectDateTime,
|
||||
required=True,
|
||||
initial=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
)
|
||||
date_end = TzAwareDateTimeField(label=_("End date"), required=False)
|
||||
date_end = forms.DateTimeField(
|
||||
label=_("End date"), widget=SelectDateTime, required=False
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.user = kwargs.pop("user", None)
|
||||
@ -191,9 +194,13 @@ class NewsForm(forms.ModelForm):
|
||||
"content": MarkdownInput,
|
||||
}
|
||||
|
||||
start_date = TzAwareDateTimeField(label=_("Start date"), required=False)
|
||||
end_date = TzAwareDateTimeField(label=_("End date"), required=False)
|
||||
until = TzAwareDateTimeField(label=_("Until"), required=False)
|
||||
start_date = forms.DateTimeField(
|
||||
label=_("Start date"), widget=SelectDateTime, required=False
|
||||
)
|
||||
end_date = forms.DateTimeField(
|
||||
label=_("End date"), widget=SelectDateTime, required=False
|
||||
)
|
||||
until = forms.DateTimeField(label=_("Until"), widget=SelectDateTime, required=False)
|
||||
|
||||
automoderation = forms.BooleanField(label=_("Automoderation"), required=False)
|
||||
|
||||
@ -258,7 +265,7 @@ class NewsEditView(CanEditMixin, UpdateView):
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
form = self.get_form()
|
||||
if form.is_valid() and "preview" not in request.POST.keys():
|
||||
if form.is_valid() and "preview" not in request.POST:
|
||||
return self.form_valid(form)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
@ -21,8 +21,6 @@
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from core.models import SithFile
|
||||
@ -37,9 +35,6 @@ class Command(BaseCommand):
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
root_path = os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
)
|
||||
files = SithFile.objects.filter(id__in=options["ids"]).all()
|
||||
for f in files:
|
||||
f._check_fs()
|
||||
|
@ -22,7 +22,7 @@
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import sass
|
||||
from django.conf import settings
|
||||
@ -34,44 +34,36 @@ class Command(BaseCommand):
|
||||
|
||||
help = "Compile scss files from static folder"
|
||||
|
||||
def compile(self, filename):
|
||||
args = {"filename": filename, "include_paths": settings.STATIC_ROOT}
|
||||
def compile(self, filename: str):
|
||||
args = {
|
||||
"filename": filename,
|
||||
"include_paths": settings.STATIC_ROOT.name,
|
||||
"output_style": "compressed",
|
||||
}
|
||||
if settings.SASS_PRECISION:
|
||||
args["precision"] = settings.SASS_PRECISION
|
||||
return sass.compile(**args)
|
||||
|
||||
def is_compilable(self, file, ext_list):
|
||||
path, ext = os.path.splitext(file)
|
||||
return ext in ext_list
|
||||
|
||||
def exec_on_folder(self, folder, func):
|
||||
to_exec = []
|
||||
for file in os.listdir(folder):
|
||||
file = os.path.join(folder, file)
|
||||
if os.path.isdir(file):
|
||||
self.exec_on_folder(file, func)
|
||||
elif self.is_compilable(file, [".scss"]):
|
||||
to_exec.append(file)
|
||||
|
||||
for file in to_exec:
|
||||
func(file)
|
||||
|
||||
def compilescss(self, file):
|
||||
print("compiling %s" % file)
|
||||
with open(file.replace(".scss", ".css"), "w") as newfile:
|
||||
newfile.write(self.compile(file))
|
||||
|
||||
def removescss(self, file):
|
||||
print("removing %s" % file)
|
||||
os.remove(file)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if os.path.isdir(settings.STATIC_ROOT):
|
||||
print("---- Compiling scss files ---")
|
||||
self.exec_on_folder(settings.STATIC_ROOT, self.compilescss)
|
||||
print("---- Removing scss files ----")
|
||||
self.exec_on_folder(settings.STATIC_ROOT, self.removescss)
|
||||
else:
|
||||
print(
|
||||
"No static folder avalaible, please use collectstatic before compiling scss"
|
||||
if not settings.STATIC_ROOT.is_dir():
|
||||
raise Exception(
|
||||
"No static folder availaible, please use collectstatic before compiling scss"
|
||||
)
|
||||
to_exec = list(settings.STATIC_ROOT.rglob("*.scss"))
|
||||
if len(to_exec) == 0:
|
||||
self.stdout.write("Nothing to compile.")
|
||||
sys.exit(0)
|
||||
self.stdout.write("---- Compiling scss files ---")
|
||||
for file in to_exec:
|
||||
# remove existing css files that will be replaced
|
||||
# keeping them while compiling the scss would break
|
||||
# import statements resolution
|
||||
css_file = file.with_suffix(".css")
|
||||
if css_file.exists():
|
||||
css_file.unlink()
|
||||
compiled_files = {file: self.compile(str(file.resolve())) for file in to_exec}
|
||||
for file, scss in compiled_files.items():
|
||||
file.replace(file.with_suffix(".css")).write_text(scss)
|
||||
self.stdout.write(
|
||||
"Files compiled : \n" + "\n- ".join(str(f) for f in compiled_files)
|
||||
)
|
||||
|
@ -21,7 +21,6 @@
|
||||
#
|
||||
#
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
@ -33,7 +32,7 @@ class Command(BaseCommand):
|
||||
help = "Output the fully rendered SYNTAX.md file"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
root_path = Path(settings.BASE_DIR)
|
||||
root_path = settings.BASE_DIR
|
||||
with open(root_path / "core/fixtures/SYNTAX.md", "r") as md:
|
||||
result = markdown(md.read())
|
||||
print(result, end="")
|
||||
|
383
core/management/commands/populate_more.py
Normal file
383
core/management/commands/populate_more.py
Normal file
@ -0,0 +1,383 @@
|
||||
import random
|
||||
from datetime import date, timedelta
|
||||
from decimal import Decimal
|
||||
from typing import Iterator
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db.models import Exists, F, Min, OuterRef, Subquery, Sum
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.utils.timezone import make_aware, now
|
||||
from faker import Faker
|
||||
|
||||
from club.models import Club, Membership
|
||||
from core.models import RealGroup, User
|
||||
from counter.models import (
|
||||
Counter,
|
||||
Customer,
|
||||
Permanency,
|
||||
Product,
|
||||
ProductType,
|
||||
Refilling,
|
||||
Selling,
|
||||
)
|
||||
from pedagogy.models import UV
|
||||
from subscription.models import Subscription
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Add more fixtures for a more complete development environment"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.faker = Faker("fr_FR")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if not settings.DEBUG:
|
||||
raise Exception("Never call this command in prod. Never.")
|
||||
|
||||
self.stdout.write("Creating users...")
|
||||
users = [
|
||||
User(
|
||||
username=self.faker.user_name(),
|
||||
first_name=self.faker.first_name(),
|
||||
last_name=self.faker.last_name(),
|
||||
date_of_birth=self.faker.date_of_birth(minimum_age=15, maximum_age=25),
|
||||
email=self.faker.email(),
|
||||
phone=self.faker.phone_number(),
|
||||
address=self.faker.address(),
|
||||
)
|
||||
for _ in range(600)
|
||||
]
|
||||
# there may a duplicate or two
|
||||
# Not a problem, we will just have 599 users instead of 600
|
||||
User.objects.bulk_create(users, ignore_conflicts=True)
|
||||
users = list(User.objects.order_by("-id")[: len(users)])
|
||||
|
||||
subscribers = random.sample(users, k=int(0.8 * len(users)))
|
||||
self.stdout.write("Creating subscriptions...")
|
||||
self.create_subscriptions(users)
|
||||
self.stdout.write("Creating club memberships...")
|
||||
users_qs = User.objects.filter(id__in=[s.id for s in subscribers])
|
||||
subscribers_now = list(
|
||||
users_qs.annotate(
|
||||
filter=Exists(
|
||||
Subscription.objects.filter(
|
||||
member_id=OuterRef("pk"), subscription_end__gte=now()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
old_subscribers = list(
|
||||
users_qs.annotate(
|
||||
filter=Exists(
|
||||
Subscription.objects.filter(
|
||||
member_id=OuterRef("pk"), subscription_end__lt=now()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
self.make_club(
|
||||
Club.objects.get(unix_name="ae"),
|
||||
random.sample(subscribers_now, k=min(30, len(subscribers_now))),
|
||||
random.sample(old_subscribers, k=min(60, len(old_subscribers))),
|
||||
)
|
||||
self.make_club(
|
||||
Club.objects.get(unix_name="troll"),
|
||||
random.sample(subscribers_now, k=min(20, len(subscribers_now))),
|
||||
random.sample(old_subscribers, k=min(80, len(old_subscribers))),
|
||||
)
|
||||
self.stdout.write("Creating uvs...")
|
||||
self.create_uvs()
|
||||
self.stdout.write("Creating products...")
|
||||
self.create_products()
|
||||
self.stdout.write("Creating sales and refills...")
|
||||
sellers = random.sample(list(User.objects.all()), 100)
|
||||
self.create_sales(sellers)
|
||||
self.stdout.write("Creating permanences...")
|
||||
self.create_permanences(sellers)
|
||||
|
||||
self.stdout.write("Done")
|
||||
|
||||
def create_subscriptions(self, users: list[User]):
|
||||
def prepare_subscription(user: User, start_date: date) -> Subscription:
|
||||
payment_method = random.choice(settings.SITH_SUBSCRIPTION_PAYMENT_METHOD)[0]
|
||||
duration = random.randint(1, 4)
|
||||
sub = Subscription(member=user, payment_method=payment_method)
|
||||
sub.subscription_start = sub.compute_start(d=start_date, duration=duration)
|
||||
sub.subscription_end = sub.compute_end(duration)
|
||||
return sub
|
||||
|
||||
subscriptions = []
|
||||
customers = []
|
||||
# first set of subscriptions
|
||||
for i, user in enumerate(users):
|
||||
sub = prepare_subscription(user, self.faker.past_date("-10y"))
|
||||
subscriptions.append(sub)
|
||||
customers.append(
|
||||
Customer(
|
||||
user=user,
|
||||
account_id=f"{9900 + i}{self.faker.random_lowercase_letter()}",
|
||||
)
|
||||
)
|
||||
while sub.subscription_end < now().date() and random.random() > 0.7:
|
||||
# 70% chances to subscribe again
|
||||
# (expect if it would make the subscription start after tomorrow)
|
||||
sub = prepare_subscription(
|
||||
user, self.faker.past_date(sub.subscription_end)
|
||||
)
|
||||
subscriptions.append(sub)
|
||||
Subscription.objects.bulk_create(subscriptions)
|
||||
Customer.objects.bulk_create(customers, ignore_conflicts=True)
|
||||
|
||||
def make_club(self, club: Club, members: list[User], old_members: list[User]):
|
||||
def zip_roles(users: list[User]) -> Iterator[tuple[User, int]]:
|
||||
roles = iter(sorted(settings.SITH_CLUB_ROLES.keys(), reverse=True))
|
||||
user_idx = 0
|
||||
while (role := next(roles)) > 2:
|
||||
# one member for each major role
|
||||
yield users[user_idx], role
|
||||
user_idx += 1
|
||||
for _ in range(int(0.3 * (len(users) - user_idx))):
|
||||
# 30% of the remaining in the board
|
||||
yield users[user_idx], 2
|
||||
user_idx += 1
|
||||
for remaining in users[user_idx + 1 :]:
|
||||
# everything else is a simple member
|
||||
yield remaining, 1
|
||||
|
||||
memberships = []
|
||||
old_members = old_members.copy()
|
||||
random.shuffle(old_members)
|
||||
for old in old_members:
|
||||
start = self.faker.date_between("-3y", "-1y")
|
||||
memberships.append(
|
||||
Membership(
|
||||
start_date=start,
|
||||
end_date=self.faker.past_date(start),
|
||||
user=old,
|
||||
role=random.choice(list(settings.SITH_CLUB_ROLES.keys())),
|
||||
club=club,
|
||||
)
|
||||
)
|
||||
for member, role in zip_roles(members):
|
||||
start = self.faker.past_date("-1y")
|
||||
memberships.append(
|
||||
Membership(
|
||||
start_date=start,
|
||||
user=member,
|
||||
role=role,
|
||||
club=club,
|
||||
)
|
||||
)
|
||||
Membership.objects.bulk_create(memberships)
|
||||
|
||||
def create_uvs(self):
|
||||
root = User.objects.get(username="root")
|
||||
categories = ["CS", "TM", "OM", "QC", "EC"]
|
||||
branches = ["TC", "GMC", "GI", "EDIM", "E", "IMSI", "HUMA"]
|
||||
languages = ["FR", "FR", "EN"]
|
||||
semesters = ["AUTUMN", "SPRING", "AUTUMN_AND_SPRING"]
|
||||
teachers = [self.faker.name() for _ in range(50)]
|
||||
uvs = []
|
||||
for _ in range(1000):
|
||||
code = (
|
||||
self.faker.random_uppercase_letter()
|
||||
+ self.faker.random_uppercase_letter()
|
||||
+ str(random.randint(10, 90))
|
||||
)
|
||||
uvs.append(
|
||||
UV(
|
||||
code=code,
|
||||
author=root,
|
||||
manager=random.choice(teachers),
|
||||
title=self.faker.text(max_nb_chars=50),
|
||||
department=random.choice(branches),
|
||||
credit_type=random.choice(categories),
|
||||
credits=6,
|
||||
semester=random.choice(semesters),
|
||||
language=random.choice(languages),
|
||||
program=self.faker.paragraph(random.randint(3, 10)),
|
||||
skills="\n* ".join(self.faker.sentences(random.randint(3, 10))),
|
||||
key_concepts="\n* ".join(
|
||||
self.faker.sentences(random.randint(3, 10))
|
||||
),
|
||||
hours_CM=random.randint(15, 40),
|
||||
hours_TD=random.randint(15, 40),
|
||||
hours_TP=random.randint(15, 40),
|
||||
hours_THE=random.randint(15, 40),
|
||||
hours_TE=random.randint(15, 40),
|
||||
)
|
||||
)
|
||||
UV.objects.bulk_create(uvs, ignore_conflicts=True)
|
||||
|
||||
def create_products(self):
|
||||
categories = []
|
||||
for _ in range(10):
|
||||
categories.append(ProductType(name=self.faker.text(max_nb_chars=30)))
|
||||
ProductType.objects.bulk_create(categories)
|
||||
categories = list(
|
||||
ProductType.objects.filter(name__in=[c.name for c in categories])
|
||||
)
|
||||
ae = Club.objects.get(unix_name="ae")
|
||||
other_clubs = random.sample(list(Club.objects.all()), k=3)
|
||||
groups = list(
|
||||
RealGroup.objects.filter(
|
||||
name__in=["Subscribers", "Old subscribers", "Public"]
|
||||
)
|
||||
)
|
||||
counters = list(
|
||||
Counter.objects.filter(name__in=["Foyer", "MDE", "La Gommette", "Eboutic"])
|
||||
)
|
||||
# 2/3 of the products are owned by AE
|
||||
clubs = [ae, ae, ae, ae, ae, ae, *other_clubs]
|
||||
products = []
|
||||
buying_groups = []
|
||||
selling_places = []
|
||||
for _ in range(200):
|
||||
price = random.randint(0, 10) + random.choice([0, 0.25, 0.5, 0.75])
|
||||
product = Product(
|
||||
name=self.faker.text(max_nb_chars=30),
|
||||
description=self.faker.text(max_nb_chars=120),
|
||||
product_type=random.choice(categories),
|
||||
code="".join(self.faker.random_letters(length=random.randint(4, 8))),
|
||||
purchase_price=price,
|
||||
selling_price=price,
|
||||
special_selling_price=price - min(0.5, price),
|
||||
club=random.choice(clubs),
|
||||
limit_age=0 if random.random() > 0.2 else 18,
|
||||
archived=bool(random.random() > 0.7),
|
||||
)
|
||||
products.append(product)
|
||||
for group in random.sample(groups, k=random.randint(0, 3)):
|
||||
# there will be products without buying groups
|
||||
# but there are also such products in the real database
|
||||
buying_groups.append(
|
||||
Product.buying_groups.through(product=product, group=group)
|
||||
)
|
||||
for counter in random.sample(counters, random.randint(0, 4)):
|
||||
selling_places.append(
|
||||
Counter.products.through(counter=counter, product=product)
|
||||
)
|
||||
Product.objects.bulk_create(products)
|
||||
Product.buying_groups.through.objects.bulk_create(buying_groups)
|
||||
Counter.products.through.objects.bulk_create(selling_places)
|
||||
|
||||
@staticmethod
|
||||
def _update_balances():
|
||||
customers = Customer.objects.annotate(
|
||||
money_in=Sum(F("refillings__amount"), default=0),
|
||||
money_out=Coalesce(
|
||||
Subquery(
|
||||
Selling.objects.filter(customer=OuterRef("pk"))
|
||||
.values("customer_id") # group by customer
|
||||
.annotate(res=Sum(F("unit_price") * F("quantity"), default=0))
|
||||
.values("res")
|
||||
),
|
||||
Decimal("0"),
|
||||
),
|
||||
).annotate(real_balance=F("money_in") - F("money_out"))
|
||||
for c in customers:
|
||||
c.amount = c.real_balance
|
||||
Customer.objects.bulk_update(customers, fields=["amount"])
|
||||
|
||||
def create_sales(self, sellers: list[User]):
|
||||
customers = list(
|
||||
Customer.objects.annotate(
|
||||
since=Subquery(
|
||||
Subscription.objects.filter(member__customer=OuterRef("pk"))
|
||||
.annotate(res=Min("subscription_start"))
|
||||
.values("res")
|
||||
)
|
||||
)
|
||||
)
|
||||
products = list(Product.objects.all())
|
||||
counters = list(
|
||||
Counter.objects.filter(name__in=["Foyer", "MDE", "La Gommette"])
|
||||
)
|
||||
sales = []
|
||||
reloads = []
|
||||
for customer in customers:
|
||||
# the longer the customer has existed, the higher the mean of nb_products
|
||||
mu = 5 + (now().year - customer.since.year) * 2
|
||||
nb_sales = max(0, int(random.normalvariate(mu=mu, sigma=mu * 5)))
|
||||
favoured_products = random.sample(products, k=(random.randint(1, 5)))
|
||||
favoured_counter = random.choice(counters)
|
||||
this_customer_sales = []
|
||||
for _ in range(nb_sales):
|
||||
product = (
|
||||
random.choice(favoured_products)
|
||||
if random.random() > 0.7
|
||||
else random.choice(products)
|
||||
)
|
||||
counter = (
|
||||
favoured_counter
|
||||
if random.random() > 0.7
|
||||
else random.choice(counters)
|
||||
)
|
||||
this_customer_sales.append(
|
||||
Selling(
|
||||
product=product,
|
||||
counter=counter,
|
||||
club_id=product.club_id,
|
||||
quantity=random.randint(1, 5),
|
||||
unit_price=product.selling_price,
|
||||
seller=random.choice(sellers),
|
||||
customer=customer,
|
||||
date=make_aware(
|
||||
self.faker.date_time_between(customer.since, now().date())
|
||||
),
|
||||
)
|
||||
)
|
||||
total_expanse = sum(s.unit_price * s.quantity for s in this_customer_sales)
|
||||
total_reloaded = 0
|
||||
while total_reloaded < total_expanse:
|
||||
amount = random.choice(list(range(5, 51, 5)))
|
||||
total_reloaded += amount
|
||||
reloads.append(
|
||||
Refilling(
|
||||
counter=random.choice(counters),
|
||||
amount=amount,
|
||||
operator=random.choice(sellers),
|
||||
customer=customer,
|
||||
date=make_aware(
|
||||
self.faker.date_time_between(customer.since, now().date())
|
||||
),
|
||||
is_validated=True,
|
||||
)
|
||||
)
|
||||
sales.extend(this_customer_sales)
|
||||
Refilling.objects.bulk_create(reloads)
|
||||
Selling.objects.bulk_create(sales)
|
||||
self._update_balances()
|
||||
|
||||
def create_permanences(self, sellers: list[User]):
|
||||
counters = list(
|
||||
Counter.objects.filter(name__in=["Foyer", "MDE", "La Gommette"])
|
||||
)
|
||||
perms = []
|
||||
for seller in sellers:
|
||||
favoured_counter = random.choice(counters)
|
||||
nb_perms = abs(int(random.normalvariate(mu=275, sigma=100)))
|
||||
active_period_start = self.faker.past_date("-10y")
|
||||
active_period_end = self.faker.date_between(
|
||||
active_period_start,
|
||||
min(now().date(), active_period_start + relativedelta(years=5)),
|
||||
)
|
||||
for _ in range(nb_perms):
|
||||
counter = (
|
||||
favoured_counter
|
||||
if random.random() > 0.8
|
||||
else random.choice(counters)
|
||||
)
|
||||
duration = self.faker.time_delta(timedelta(hours=1))
|
||||
start = make_aware(
|
||||
self.faker.date_time_between(active_period_start, active_period_end)
|
||||
)
|
||||
perms.append(
|
||||
Permanency(
|
||||
counter=counter, user=seller, start=start, end=start + duration
|
||||
)
|
||||
)
|
||||
Permanency.objects.bulk_create(perms)
|
@ -21,7 +21,6 @@
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
@ -37,9 +36,6 @@ class Command(BaseCommand):
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
root_path = os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
)
|
||||
files = SithFile.objects.filter(id__in=options["ids"]).all()
|
||||
for f in files:
|
||||
f._repair_fs()
|
||||
|
@ -13,28 +13,32 @@
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management import call_command
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Set up a new instance of the Sith AE"
|
||||
help = "Set up the development environment."
|
||||
|
||||
def handle(self, *args, **options):
|
||||
root_path = os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
)
|
||||
try:
|
||||
os.mkdir(os.path.join(root_path) + "/data")
|
||||
print("Data dir created")
|
||||
except Exception as e:
|
||||
repr(e)
|
||||
try:
|
||||
os.remove(os.path.join(root_path, "db.sqlite3"))
|
||||
print("db.sqlite3 deleted")
|
||||
except Exception as e:
|
||||
repr(e)
|
||||
if not settings.DEBUG:
|
||||
raise Exception("Never call this command in prod. Never.")
|
||||
data_dir = settings.BASE_DIR / "data"
|
||||
settings.EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend"
|
||||
if not data_dir.is_dir():
|
||||
data_dir.mkdir()
|
||||
db_path = settings.BASE_DIR / "db.sqlite3"
|
||||
if db_path.exists():
|
||||
call_command("flush", "--noinput")
|
||||
self.stdout.write("Existing database reset")
|
||||
call_command("migrate")
|
||||
self.stdout.write("Add the base fixtures.")
|
||||
call_command("populate")
|
||||
self.stdout.write("Generate additional random fixtures")
|
||||
call_command("populate_more")
|
||||
self.stdout.write("Build the xapian index")
|
||||
call_command("rebuild_index", "--noinput")
|
||||
|
||||
settings.EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
self.stdout.write("Setup complete!")
|
||||
|
@ -27,6 +27,7 @@ import importlib
|
||||
import os
|
||||
import unicodedata
|
||||
from datetime import date, timedelta
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from django.conf import settings
|
||||
@ -56,8 +57,6 @@ from django.utils.html import escape
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
|
||||
from core import utils
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from club.models import Club
|
||||
|
||||
@ -377,7 +376,9 @@ class User(AbstractBaseUser):
|
||||
USERNAME_FIELD = "username"
|
||||
|
||||
def promo_has_logo(self):
|
||||
return utils.file_exist("./core/static/core/img/promo_%02d.png" % self.promo)
|
||||
return Path(
|
||||
settings.BASE_DIR / f"core/static/core/img/promo_{self.promo}.png"
|
||||
).exists()
|
||||
|
||||
def has_module_perms(self, package_name):
|
||||
return self.is_active
|
||||
|
@ -22,7 +22,6 @@
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
@ -37,7 +36,7 @@ class ScssFinder(FileSystemFinder):
|
||||
|
||||
def __init__(self, apps=None, *args, **kwargs):
|
||||
location = settings.STATIC_ROOT
|
||||
if not os.path.isdir(location):
|
||||
if not location.is_dir():
|
||||
return
|
||||
self.locations = [("", location)]
|
||||
self.storages = OrderedDict()
|
||||
|
@ -21,61 +21,35 @@
|
||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
#
|
||||
|
||||
import os
|
||||
from urllib.parse import urljoin
|
||||
import functools
|
||||
from pathlib import Path
|
||||
|
||||
import sass
|
||||
from django.conf import settings
|
||||
from django.core.files.base import ContentFile
|
||||
from django.templatetags.static import static
|
||||
from django.utils.encoding import force_bytes, iri_to_uri
|
||||
from django_jinja.builtins.filters import static
|
||||
|
||||
from core.scss.storage import ScssFileStorage, find_file
|
||||
|
||||
|
||||
class ScssProcessor(object):
|
||||
"""If DEBUG mode enabled : compile the scss file
|
||||
Else : give the path of the corresponding css supposed to already be compiled
|
||||
Don't forget to use compilestatics to compile scss for production.
|
||||
"""
|
||||
@functools.cache
|
||||
def _scss_storage():
|
||||
return ScssFileStorage()
|
||||
|
||||
prefix = iri_to_uri(getattr(settings, "STATIC_URL", "/static/"))
|
||||
storage = ScssFileStorage()
|
||||
scss_extensions = [".scss"]
|
||||
|
||||
def __init__(self, path=None):
|
||||
self.path = path
|
||||
|
||||
def _convert_scss(self):
|
||||
basename, ext = os.path.splitext(self.path)
|
||||
css_filename = self.path.replace(".scss", ".css")
|
||||
url = urljoin(self.prefix, css_filename)
|
||||
|
||||
if not settings.DEBUG:
|
||||
return url
|
||||
|
||||
if ext not in self.scss_extensions:
|
||||
return static(self.path)
|
||||
|
||||
# Compilation on the fly
|
||||
def process_scss_path(path: Path):
|
||||
css_path = path.with_suffix(".css")
|
||||
if settings.DEBUG:
|
||||
compile_args = {
|
||||
"filename": find_file(self.path),
|
||||
"filename": find_file(path),
|
||||
"include_paths": settings.SASS_INCLUDE_FOLDERS,
|
||||
}
|
||||
if settings.SASS_PRECISION:
|
||||
compile_args["precision"] = settings.SASS_PRECISION
|
||||
content = sass.compile(**compile_args)
|
||||
content = force_bytes(content)
|
||||
|
||||
if self.storage.exists(css_filename):
|
||||
self.storage.delete(css_filename)
|
||||
self.storage.save(css_filename, ContentFile(content))
|
||||
|
||||
return url
|
||||
|
||||
def get_converted_scss(self):
|
||||
if self.path:
|
||||
return self._convert_scss()
|
||||
else:
|
||||
return ""
|
||||
storage = _scss_storage()
|
||||
if storage.exists(css_path):
|
||||
storage.delete(css_path)
|
||||
storage.save(css_path, ContentFile(content))
|
||||
return static(css_path)
|
||||
|
@ -1,149 +1,149 @@
|
||||
body{
|
||||
position: absolute;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#slideshow{
|
||||
position: relative;
|
||||
background-color: lightgrey;
|
||||
position: relative;
|
||||
background-color: lightgrey;
|
||||
|
||||
height: 100%;
|
||||
|
||||
*{
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&:hover{
|
||||
|
||||
&::before{
|
||||
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
z-index: 10;
|
||||
|
||||
content: "Click to expand";
|
||||
|
||||
color: white;
|
||||
background-color: rgba(black, 0.5);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.fullscreen{
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: none;
|
||||
|
||||
*{
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&:hover{
|
||||
|
||||
&::before{
|
||||
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
z-index: 10;
|
||||
|
||||
content: "Click to expand";
|
||||
|
||||
color: white;
|
||||
background-color: rgba(black, 0.5);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.fullscreen{
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: none;
|
||||
|
||||
&:before{
|
||||
display:none;
|
||||
}
|
||||
|
||||
#slides{
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
&:before{
|
||||
display:none;
|
||||
}
|
||||
|
||||
#slides{
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.slide{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
|
||||
top: 0px;
|
||||
|
||||
background-color: grey;
|
||||
transition: left 1s ease-out;
|
||||
|
||||
img{
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.slide.left{
|
||||
left: -100%;
|
||||
}
|
||||
|
||||
.slide.center{
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.slide.right{
|
||||
left: 100%;
|
||||
transition: none;
|
||||
}
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#progress_bullets{
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
#slides{
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.slide{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
margin-bottom: 10px;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
|
||||
.bullet{
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
top: 0px;
|
||||
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
background-color: grey;
|
||||
transition: left 1s ease-out;
|
||||
|
||||
border-radius: 50%;
|
||||
|
||||
background-color: grey;
|
||||
|
||||
&.active{
|
||||
background-color: #c99836;
|
||||
}
|
||||
}
|
||||
img{
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
#progress_bar{
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
height: 10px;
|
||||
background-color: #304c83;
|
||||
|
||||
&.init{
|
||||
width: 0px;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&.progress{
|
||||
width: 100%;
|
||||
transition: width 10s linear;
|
||||
}
|
||||
.slide.left{
|
||||
left: -100%;
|
||||
}
|
||||
|
||||
.slide.center{
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.slide.right{
|
||||
left: 100%;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#progress_bullets{
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
margin-bottom: 10px;
|
||||
|
||||
.bullet{
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
|
||||
border-radius: 50%;
|
||||
|
||||
background-color: grey;
|
||||
|
||||
&.active{
|
||||
background-color: #c99836;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#progress_bar{
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
height: 10px;
|
||||
background-color: #304c83;
|
||||
|
||||
&.init{
|
||||
width: 0px;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&.progress{
|
||||
width: 100%;
|
||||
transition: width 10s linear;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
30
core/static/core/colors.scss
Normal file
30
core/static/core/colors.scss
Normal file
@ -0,0 +1,30 @@
|
||||
$first-color: hsl(220, 100%, 50%);
|
||||
$second-color: hsl(48, 100%, 67%);
|
||||
$primary-color: hsl(219.9, 53.7%, 50%);
|
||||
$secondary-color: hsl(204, 64%, 44%);
|
||||
$primary-color-text: hsl(0, 0%, 100%);
|
||||
$secondary-color-text: hsla(0, 0%, 0%, 0.87);
|
||||
|
||||
$primary-light-color: hsl(219.8, 46.4%, 64.9%);
|
||||
$primary-dark-color: hsl(203, 75%, 40%);
|
||||
|
||||
$secondary-light-color: hsl(40, 68%, 65%);
|
||||
$secondary-dark-color: hsl(40, 68%, 35%);
|
||||
|
||||
$primary-neutral-color: hsl(219.6, 20.8%, 50%);
|
||||
$primary-neutral-light-color: hsl(0, 0%, 94%);
|
||||
$primary-neutral-dark-color: hsl(210, 29%, 29%);
|
||||
|
||||
$secondary-neutral-color: hsl(204, 64%, 44%);
|
||||
$secondary-neutral-light-color: hsl(0, 0%, 91%);
|
||||
$secondary-neutral-dark-color: hsl(40, 57.6%, 17%);
|
||||
|
||||
$white-color: hsl(219.6, 20.8%, 98%);
|
||||
$black-color: hsl(0, 0%, 17%);
|
||||
|
||||
$faceblue: hsl(221, 44%, 41%);
|
||||
$twitblue: hsl(206, 82%, 63%);
|
||||
|
||||
$shadow-color: rgb(223, 223, 223);
|
||||
|
||||
$background-button-color: hsl(0, 0%, 95%);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
core/static/core/js/jszip/jszip-utils.min.js
vendored
Normal file
1
core/static/core/js/jszip/jszip-utils.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JSZipUtils=e():"undefined"!=typeof global?global.JSZipUtils=e():"undefined"!=typeof self&&(self.JSZipUtils=e())}(function(){return function o(i,f,u){function s(n,e){if(!f[n]){if(!i[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(a)return a(n,!0);throw new Error("Cannot find module '"+n+"'")}var r=f[n]={exports:{}};i[n][0].call(r.exports,function(e){var t=i[n][1][e];return s(t||e)},r,r.exports,o,i,f,u)}return f[n].exports}for(var a="function"==typeof require&&require,e=0;e<u.length;e++)s(u[e]);return s}({1:[function(e,t,n){"use strict";var u={};function r(){try{return new window.XMLHttpRequest}catch(e){}}u._getBinaryFromXHR=function(e){return e.response||e.responseText};var s="undefined"!=typeof window&&window.ActiveXObject?function(){return r()||function(){try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(e){}}()}:r;u.getBinaryContent=function(t,n){var e,r,o,i;"function"==typeof(n=n||{})?(i=n,n={}):"function"==typeof n.callback&&(i=n.callback),i||"undefined"==typeof Promise?(r=function(e){i(null,e)},o=function(e){i(e,null)}):e=new Promise(function(e,t){r=e,o=t});try{var f=s();f.open("GET",t,!0),"responseType"in f&&(f.responseType="arraybuffer"),f.overrideMimeType&&f.overrideMimeType("text/plain; charset=x-user-defined"),f.onreadystatechange=function(e){if(4===f.readyState)if(200===f.status||0===f.status)try{r(u._getBinaryFromXHR(f))}catch(e){o(new Error(e))}else o(new Error("Ajax error for "+t+" : "+this.status+" "+this.statusText))},n.progress&&(f.onprogress=function(e){n.progress({path:t,originalEvent:e,percent:e.loaded/e.total*100,loaded:e.loaded,total:e.total})}),f.send()}catch(e){o(new Error(e),null)}return e},t.exports=u},{}]},{},[1])(1)});
|
13
core/static/core/js/jszip/jszip.min.js
vendored
Normal file
13
core/static/core/js/jszip/jszip.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
21
core/static/core/js/native-file-system-adapter/LICENSE
Normal file
21
core/static/core/js/native-file-system-adapter/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Jimmy Wärting
|
||||
|
||||
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.
|
1
core/static/core/js/native-file-system-adapter/mod.js
Normal file
1
core/static/core/js/native-file-system-adapter/mod.js
Normal file
@ -0,0 +1 @@
|
||||
export*from"./src/es6.js";
|
0
core/static/core/js/native-file-system-adapter/mod.min.js
vendored
Normal file
0
core/static/core/js/native-file-system-adapter/mod.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
import FileSystemHandle from"./FileSystemHandle.js";import{errors}from"./util.js";const{GONE:GONE,MOD_ERR:MOD_ERR}=errors,kAdapter=Symbol("adapter");class FileSystemDirectoryHandle extends FileSystemHandle{[kAdapter];constructor(e){super(e),this[kAdapter]=e}async getDirectoryHandle(e,t={}){if(""===e)throw new TypeError("Name can't be an empty string.");if("."===e||".."===e||e.includes("/"))throw new TypeError("Name contains invalid characters.");t.create=!!t.create;const r=await this[kAdapter].getDirectoryHandle(e,t);return new FileSystemDirectoryHandle(r)}async*entries(){const{FileSystemFileHandle:e}=await import("./FileSystemFileHandle.js");for await(const[t,r]of this[kAdapter].entries())yield[r.name,"file"===r.kind?new e(r):new FileSystemDirectoryHandle(r)]}async*getEntries(){const{FileSystemFileHandle:e}=await import("./FileSystemFileHandle.js");console.warn("deprecated, use .entries() instead");for await(let t of this[kAdapter].entries())yield"file"===t.kind?new e(t):new FileSystemDirectoryHandle(t)}async getFileHandle(e,t={}){const{FileSystemFileHandle:r}=await import("./FileSystemFileHandle.js");if(""===e)throw new TypeError("Name can't be an empty string.");if("."===e||".."===e||e.includes("/"))throw new TypeError("Name contains invalid characters.");t.create=!!t.create;return new r(await this[kAdapter].getFileHandle(e,t))}async removeEntry(e,t={}){if(""===e)throw new TypeError("Name can't be an empty string.");if("."===e||".."===e||e.includes("/"))throw new TypeError("Name contains invalid characters.");return t.recursive=!!t.recursive,this[kAdapter].removeEntry(e,t)}async resolve(e){if(await e.isSameEntry(this))return[];const t=[{handle:this,path:[]}];for(;t.length;){let{handle:r,path:n}=t.pop();for await(const a of r.values()){if(await a.isSameEntry(e))return[...n,a.name];"directory"===a.kind&&t.push({handle:a,path:[...n,a.name]})}}return null}async*keys(){for await(const[e]of this[kAdapter].entries())yield e}async*values(){for await(const[e,t]of this)yield t}[Symbol.asyncIterator](){return this.entries()}}if(Object.defineProperty(FileSystemDirectoryHandle.prototype,Symbol.toStringTag,{value:"FileSystemDirectoryHandle",writable:!1,enumerable:!1,configurable:!0}),Object.defineProperties(FileSystemDirectoryHandle.prototype,{getDirectoryHandle:{enumerable:!0},entries:{enumerable:!0},getFileHandle:{enumerable:!0},removeEntry:{enumerable:!0}}),globalThis.FileSystemDirectoryHandle){const e=globalThis.FileSystemDirectoryHandle.prototype;async function ensureDoActuallyStillExist(e){const t=await navigator.storage.getDirectory();if(null===await t.resolve(e))throw new DOMException(...GONE)}e.resolve=async function(e){if(await e.isSameEntry(this))return[];const t=[{handle:this,path:[]}];for(;t.length;){let{handle:r,path:n}=t.pop();for await(const a of r.values()){if(await a.isSameEntry(e))return[...n,a.name];"directory"===a.kind&&t.push({handle:a,path:[...n,a.name]})}}return null};const t=e.entries;e.entries=async function*(){await ensureDoActuallyStillExist(this),yield*t.call(this)},e[Symbol.asyncIterator]=async function*(){yield*this.entries()};const r=e.removeEntry;e.removeEntry=async function(e,n={}){return r.call(this,e,n).catch((async e=>{if(e instanceof DOMException&&"UnknownError"===e.name&&!n.recursive){if(!(await t.call(this).next()).done)throw new DOMException(...MOD_ERR)}throw e}))}}export default FileSystemDirectoryHandle;export{FileSystemDirectoryHandle};
|
@ -0,0 +1 @@
|
||||
import FileSystemHandle from"./FileSystemHandle.js";import FileSystemWritableFileStream from"./FileSystemWritableFileStream.js";import{errors}from"./util.js";const{INVALID:INVALID,SYNTAX:SYNTAX,GONE:GONE}=errors,kAdapter=Symbol("adapter");class FileSystemFileHandle extends FileSystemHandle{[kAdapter];constructor(e){super(e),this[kAdapter]=e}async createWritable(e={}){return new FileSystemWritableFileStream(await this[kAdapter].createWritable(e))}async getFile(){return this[kAdapter].getFile()}}if(Object.defineProperty(FileSystemFileHandle.prototype,Symbol.toStringTag,{value:"FileSystemFileHandle",writable:!1,enumerable:!1,configurable:!0}),Object.defineProperties(FileSystemFileHandle.prototype,{createWritable:{enumerable:!0},getFile:{enumerable:!0}}),globalThis.FileSystemFileHandle&&!globalThis.FileSystemFileHandle.prototype.createWritable){const e=new WeakMap;let t;const a=()=>{let e,t;onmessage=async a=>{const i=a.ports[0],r=a.data;switch(r.type){case"open":const a=r.name;let i=await navigator.storage.getDirectory();for(const e of r.path)i=await i.getDirectoryHandle(e);e=await i.getFileHandle(a),t=await e.createSyncAccessHandle();break;case"write":t.write(r.data,{at:r.position}),t.flush();break;case"truncate":t.truncate(r.size);break;case"abort":case"close":t.close()}i.postMessage(0)}};globalThis.FileSystemFileHandle.prototype.createWritable=async function(i){if(!t){const e=`(${a.toString()})()`,i=new Blob([e],{type:"text/javascript"});t=URL.createObjectURL(i)}const r=new Worker(t,{type:"module"});let n=0;const s=new TextEncoder;let o=await this.getFile().then((e=>e.size));const l=e=>new Promise(((t,a)=>{const i=new MessageChannel;i.port1.onmessage=e=>{e.data instanceof Error?a(e.data):t(e.data),i.port1.close(),i.port2.close(),i.port1.onmessage=null},r.postMessage(e,[i.port2])})),c=await navigator.storage.getDirectory(),p=await e.get(this),y=await c.resolve(p);if(null===y)throw new DOMException(...GONE);let d;await l({type:"open",path:y,name:this.name}),!1===i?.keepExistingData&&(await l({type:"truncate",size:0}),o=0);return new FileSystemWritableFileStream({start:e=>{d=e},async write(e){if("write"===(e=e?.constructor===Object?{...e}:{type:"write",data:e,position:n}).type){if(!("data"in e))throw await l({type:"close"}),new DOMException(...SYNTAX("write requires a data argument"));if(e.position??=n,"string"==typeof e.data)e.data=s.encode(e.data);else if(e.data instanceof ArrayBuffer)e.data=new Uint8Array(e.data);else if(e.data instanceof Uint8Array||!ArrayBuffer.isView(e.data)){if(!(e.data instanceof Uint8Array)){const t=await new Response(e.data).arrayBuffer();e.data=new Uint8Array(t)}}else e.data=new Uint8Array(e.data.buffer,e.data.byteOffset,e.data.byteLength);Number.isInteger(e.position)&&e.position>=0&&(n=e.position),n+=e.data.byteLength,o+=e.data.byteLength}else{if("seek"===e.type){if(Number.isInteger(e.position)&&e.position>=0){if(o<e.position)throw new DOMException(...INVALID);return console.log("seeking",e),void(n=e.position)}throw await l({type:"close"}),new DOMException(...SYNTAX("seek requires a position argument"))}if("truncate"===e.type){if(!(Number.isInteger(e.size)&&e.size>=0))throw await l({type:"close"}),new DOMException(...SYNTAX("truncate requires a size argument"));o=e.size,n>o&&(n=o)}}await l(e)},async close(){await l({type:"close"}),r.terminate()},async abort(e){await l({type:"abort",reason:e}),r.terminate()}})};const i=FileSystemDirectoryHandle.prototype.getFileHandle;FileSystemDirectoryHandle.prototype.getFileHandle=async function(...t){const a=await i.call(this,...t);return e.set(a,this),a}}export default FileSystemFileHandle;export{FileSystemFileHandle};
|
@ -0,0 +1 @@
|
||||
const kAdapter=Symbol("adapter");class FileSystemHandle{[kAdapter];name;kind;constructor(e){this.kind=e.kind,this.name=e.name,this[kAdapter]=e}async queryPermission(e={}){const{mode:r="read"}=e,t=this[kAdapter];if(t.queryPermission)return t.queryPermission({mode:r});if("read"===r)return"granted";if("readwrite"===r)return t.writable?"granted":"denied";throw new TypeError(`Mode ${r} must be 'read' or 'readwrite'`)}async requestPermission({mode:e="read"}={}){const r=this[kAdapter];if(r.requestPermission)return r.requestPermission({mode:e});if("read"===e)return"granted";if("readwrite"===e)return r.writable?"granted":"denied";throw new TypeError(`Mode ${e} must be 'read' or 'readwrite'`)}async remove(e={}){await this[kAdapter].remove(e)}async isSameEntry(e){return this===e||!(!e||"object"!=typeof e||this.kind!==e.kind||!e[kAdapter])&&this[kAdapter].isSameEntry(e[kAdapter])}}Object.defineProperty(FileSystemHandle.prototype,Symbol.toStringTag,{value:"FileSystemHandle",writable:!1,enumerable:!1,configurable:!0}),globalThis.FileSystemHandle&&(globalThis.FileSystemHandle.prototype.queryPermission??=function(e){return"granted"});export default FileSystemHandle;export{FileSystemHandle};
|
@ -0,0 +1 @@
|
||||
import config from"./config.js";const{WritableStream:WritableStream}=config;class FileSystemWritableFileStream extends WritableStream{#e;constructor(e){super(e),this.#e=e,Object.setPrototypeOf(this,FileSystemWritableFileStream.prototype),this._closed=!1}async close(){this._closed=!0;const e=this.getWriter(),t=e.close();return e.releaseLock(),t}seek(e){return this.write({type:"seek",position:e})}truncate(e){return this.write({type:"truncate",size:e})}write(e){if(this._closed)return Promise.reject(new TypeError("Cannot write to a CLOSED writable stream"));const t=this.getWriter(),r=t.write(e);return t.releaseLock(),r}}Object.defineProperty(FileSystemWritableFileStream.prototype,Symbol.toStringTag,{value:"FileSystemWritableFileStream",writable:!1,enumerable:!1,configurable:!0}),Object.defineProperties(FileSystemWritableFileStream.prototype,{close:{enumerable:!0},seek:{enumerable:!0},truncate:{enumerable:!0},write:{enumerable:!0}}),!globalThis.FileSystemFileHandle||globalThis.FileSystemFileHandle.prototype.createWritable||globalThis.FileSystemWritableFileStream||(globalThis.FileSystemWritableFileStream=FileSystemWritableFileStream);export default FileSystemWritableFileStream;export{FileSystemWritableFileStream};
|
@ -0,0 +1 @@
|
||||
import{errors}from"../util.js";const{INVALID:INVALID,GONE:GONE,MISMATCH:MISMATCH,MOD_ERR:MOD_ERR,SYNTAX:SYNTAX,SECURITY:SECURITY,DISALLOWED:DISALLOWED}=errors;export class Sink{constructor(){}write(e){}close(){}}export class FileHandle{constructor(){this._path=""}async getFile(){return new File([],"")}async createWritable(){}async isSameEntry(e){return e._path===this._path}}export class FolderHandle{constructor(){this._path=""}async*entries(){yield}async isSameEntry(e){return e._path===this._path}async getDirectoryHandle(e,r){return new FolderHandle}async getFileHandle(e,r){return new FileHandle}async removeEntry(e,r){}}const fs=new FolderHandle("");export default()=>fs;
|
@ -0,0 +1 @@
|
||||
import{errors}from"../util.js";const{INVALID:INVALID,GONE:GONE,MISMATCH:MISMATCH,MOD_ERR:MOD_ERR,SYNTAX:SYNTAX}=errors,DIR={headers:{"content-type":"dir"}},FILE=()=>({headers:{"content-type":"file","last-modified":Date.now()}}),hasOwn=Object.prototype.hasOwnProperty;class Sink{constructor(e,t,i){this._cache=e,this.path=t,this.size=i.size,this.position=0,this.file=i}write(e,t){if("object"==typeof e)if("write"===e.type){if(Number.isInteger(e.position)&&e.position>=0&&(this.size<e.position&&(this.file=new Blob([this.file,new ArrayBuffer(e.position-this.size)])),this.position=e.position),!("data"in e))throw new DOMException(...SYNTAX("write requires a data argument"));e=e.data}else{if("seek"===e.type){if(Number.isInteger(e.position)&&e.position>=0){if(this.size<e.position)throw new DOMException(...INVALID);return void(this.position=e.position)}throw new DOMException(...SYNTAX("seek requires a position argument"))}if("truncate"===e.type){if(Number.isInteger(e.size)&&e.size>=0){let t=this.file;return t=e.size<this.size?t.slice(0,e.size):new File([t,new Uint8Array(e.size-this.size)],t.name),this.size=t.size,this.position>t.size&&(this.position=t.size),void(this.file=t)}throw new DOMException(...SYNTAX("truncate requires a size argument"))}}e=new Blob([e]);let i=this.file;const s=i.slice(0,this.position),n=i.slice(this.position+e.size);let a=this.position-s.size;a<0&&(a=0),i=new File([s,new Uint8Array(a),e,n],i.name),this.size=i.size,this.position+=e.size,this.file=i}async close(){const[e]=await this._cache.keys(this.path);if(!e)throw new DOMException(...GONE);return this._cache.put(this.path,new Response(this.file,FILE()))}}export class FileHandle{constructor(e,t){this._cache=t,this.path=e,this.kind="file",this.writable=!0,this.readable=!0}get name(){return this.path.split("/").pop()}async isSameEntry(e){return this.path===e.path}async getFile(){const e=await this._cache.match(this.path);if(!e)throw new DOMException(...GONE);const t=await e.blob();return new File([t],this.name,{lastModified:+e.headers.get("last-modified")})}async createWritable(e){const[t]=await this._cache.keys(this.path);if(!t)throw new DOMException(...GONE);return new Sink(this._cache,this.path,e.keepExistingData?await this.getFile():new File([],this.name))}}export class FolderHandle{constructor(e,t){this._dir=e,this.writable=!0,this.readable=!0,this._cache=t,this.kind="directory",this.name=e.split("/").pop()}async*entries(){for(const[e,t]of Object.entries(await this._tree))yield[e.split("/").pop(),t?new FileHandle(e,this._cache):new FolderHandle(e,this._cache)]}async isSameEntry(e){return this._dir===e._dir}async getDirectoryHandle(e,t){const i=this._dir.endsWith("/")?this._dir+e:`${this._dir}/${e}`,s=await this._tree;if(hasOwn.call(s,i)){if(s[i])throw new DOMException(...MISMATCH);return new FolderHandle(i,this._cache)}if(t.create)return s[i]=!1,await this._cache.put(i,new Response("{}",DIR)),await this._save(s),new FolderHandle(i,this._cache);throw new DOMException(...GONE)}get _tree(){return this._cache.match(this._dir).then((e=>e.json())).catch((e=>{throw new DOMException(...GONE)}))}_save(e){return this._cache.put(this._dir,new Response(JSON.stringify(e),DIR))}async getFileHandle(e,t){const i=this._dir.endsWith("/")?this._dir+e:`${this._dir}/${e}`,s=await this._tree;if(hasOwn.call(s,i)){if(!s[i])throw new DOMException(...MISMATCH);return new FileHandle(i,this._cache)}if(t.create){const e=await this._tree;return e[i]=!0,await this._cache.put(i,new Response("",FILE())),await this._save(e),new FileHandle(i,this._cache)}throw new DOMException(...GONE)}async removeEntry(e,t){const i=await this._tree,s=this._dir.endsWith("/")?this._dir+e:`${this._dir}/${e}`;if(!hasOwn.call(i,s))throw new DOMException(...GONE);if(t.recursive){const e=[...Object.entries(i)];for(;e.length;){const[t,i]=e.pop();if(i)await this._cache.delete(t);else{const i=await this._cache.match(t).then((e=>e.json()));e.push(...Object.entries(i))}}delete i[s]}else{const e=i[s];if(delete i[s],e)await this._cache.delete(s);else{const e=await this._cache.match(s).then((e=>e.json()));if(Object.keys(e).length)throw new DOMException(...MOD_ERR);await this._cache.delete(s)}}await this._save(i)}}export default async function(){const e=await caches.open("sandboxed-fs");return await e.match("/")||await e.put("/",new Response("{}",DIR)),new FolderHandle(location.origin+"/",e)}
|
@ -0,0 +1 @@
|
||||
import{join,basename}from"https://deno.land/std@0.108.0/path/mod.ts";import{errors}from"../util.js";const{INVALID:INVALID,GONE:GONE,MISMATCH:MISMATCH,MOD_ERR:MOD_ERR,SYNTAX:SYNTAX}=errors;async function fileFrom(t){const e=Deno.readFileSync(t),i=await Deno.stat(t);return new File([e],basename(t),{lastModified:Number(i.mtime)})}export class Sink{constructor(t,e){this.fileHandle=t,this.size=e,this.position=0}async abort(){await this.fileHandle.close()}async write(t){if("object"==typeof t)if("write"===t.type){if(Number.isInteger(t.position)&&t.position>=0&&(this.position=t.position),!("data"in t))throw await this.fileHandle.close(),new DOMException(...SYNTAX("write requires a data argument"));t=t.data}else{if("seek"===t.type){if(Number.isInteger(t.position)&&t.position>=0){if(this.size<t.position)throw new DOMException(...INVALID);return void(this.position=t.position)}throw await this.fileHandle.close(),new DOMException(...SYNTAX("seek requires a position argument"))}if("truncate"===t.type){if(Number.isInteger(t.size)&&t.size>=0)return await this.fileHandle.truncate(t.size),this.size=t.size,void(this.position>this.size&&(this.position=this.size));throw await this.fileHandle.close(),new DOMException(...SYNTAX("truncate requires a size argument"))}}if(t instanceof ArrayBuffer)t=new Uint8Array(t);else if("string"==typeof t)t=(new TextEncoder).encode(t);else if(t instanceof Blob){await this.fileHandle.seek(this.position,Deno.SeekMode.Start);for await(const e of t.stream()){const t=await this.fileHandle.write(e);this.position+=t,this.size+=t}return}await this.fileHandle.seek(this.position,Deno.SeekMode.Start);const e=await this.fileHandle.write(t);this.position+=e,this.size+=e}async close(){await this.fileHandle.close()}}export class FileHandle{#t;constructor(t,e){this.#t=t,this.name=e,this.kind="file"}async getFile(){return await Deno.stat(this.#t).catch((t=>{if("NotFound"===t.name)throw new DOMException(...GONE)})),fileFrom(this.#t)}async isSameEntry(t){return this.#t===this.#e.apply(t)}#e(){return this.#t}async createWritable(t){const e=await Deno.open(this.#t,{write:!0,truncate:!t.keepExistingData}).catch((t=>{if("NotFound"===t.name)throw new DOMException(...GONE);throw t})),{size:i}=await e.stat();return new Sink(e,i)}}export class FolderHandle{#t="";constructor(t,e=""){this.name=e,this.kind="directory",this.#t=join(t)}async isSameEntry(t){return this.#t===this.#e.apply(t)}#e(){return this.#t}async*entries(){const t=this.#t;try{for await(const e of Deno.readDir(t)){const{name:i}=e,n=join(t,i),o=await Deno.lstat(n);o.isFile?yield[i,new FileHandle(n,i)]:o.isDirectory&&(yield[i,new FolderHandle(n,i)])}}catch(t){throw"NotFound"===t.name?new DOMException(...GONE):t}}async getDirectoryHandle(t,e){const i=join(this.#t,t),n=await Deno.lstat(i).catch((t=>{if("NotFound"!==t.name)throw t})),o=n?.isDirectory;if(n&&o)return new FolderHandle(i,t);if(n&&!o)throw new DOMException(...MISMATCH);if(!e.create)throw new DOMException(...GONE);return await Deno.mkdir(i),new FolderHandle(i,t)}async getFileHandle(t,e){const i=join(this.#t,t),n=await Deno.lstat(i).catch((t=>{if("NotFound"!==t.name)throw t})),o=n?.isFile;if(n&&o)return new FileHandle(i,t);if(n&&!o)throw new DOMException(...MISMATCH);if(!e.create)throw new DOMException(...GONE);return(await Deno.open(i,{create:!0,write:!0})).close(),new FileHandle(i,t)}async queryPermission(){return"granted"}async removeEntry(t,e){const i=join(this.#t,t);(await Deno.lstat(i).catch((t=>{if("NotFound"===t.name)throw new DOMException(...GONE);throw t}))).isDirectory?e.recursive?await Deno.remove(i,{recursive:!0}).catch((t=>{if("ENOTEMPTY"===t.code)throw new DOMException(...MOD_ERR);throw t})):await Deno.remove(i).catch((()=>{throw new DOMException(...MOD_ERR)})):await Deno.remove(i)}}export default t=>new FolderHandle(join(Deno.cwd(),t));
|
@ -0,0 +1 @@
|
||||
import{errors}from"../util.js";import config from"../config.js";const{WritableStream:WritableStream,TransformStream:TransformStream,DOMException:DOMException,Blob:Blob}=config,{GONE:GONE}=errors,isOldSafari=/constructor/i.test(window.HTMLElement);export class FileHandle{constructor(e="unkown"){this.name=e,this.kind="file"}async getFile(){throw new DOMException(...GONE)}async isSameEntry(e){return this===e}async createWritable(e={}){const t=await(navigator.serviceWorker?.getRegistration()),r=document.createElement("a"),s=new TransformStream,a=s.writable;if(r.download=this.name,isOldSafari||!t){let e=[];s.readable.pipeTo(new WritableStream({write(t){e.push(new Blob([t]))},close(){const t=new Blob(e,{type:"application/octet-stream; charset=utf-8"});e=[],r.href=URL.createObjectURL(t),r.click(),setTimeout((()=>URL.revokeObjectURL(r.href)),1e4)}}))}else{const{writable:r,readablePort:a}=new RemoteWritableStream(WritableStream),o=encodeURIComponent(this.name).replace(/['()]/g,escape).replace(/\*/g,"%2A"),n={"content-disposition":"attachment; filename*=UTF-8''"+o,"content-type":"application/octet-stream; charset=utf-8",...e.size?{"content-length":e.size}:{}},i=setTimeout((()=>t.active.postMessage(0)),1e4);s.readable.pipeThrough(new TransformStream({transform(e,t){if(e instanceof Uint8Array)return t.enqueue(e);const r=new Response(e).body.getReader(),s=e=>r.read().then((e=>e.done?0:s(t.enqueue(e.value))));return s()}})).pipeTo(r).finally((()=>{clearInterval(i)})),t.active.postMessage({url:t.scope+o,headers:n,readablePort:a},[a]);const c=document.createElement("iframe");c.hidden=!0,c.src=t.scope+o,document.body.appendChild(c)}return a.getWriter()}}const WRITE=0,PULL=0,ERROR=1,ABORT=1,CLOSE=2;class MessagePortSink{constructor(e){e.onmessage=e=>this._onMessage(e.data),this._port=e,this._resetReady()}start(e){return this._controller=e,this._readyPromise}write(e){const t={type:0,chunk:e};return this._port.postMessage(t,[e.buffer]),this._resetReady(),this._readyPromise}close(){this._port.postMessage({type:2}),this._port.close()}abort(e){this._port.postMessage({type:1,reason:e}),this._port.close()}_onMessage(e){0===e.type&&this._resolveReady(),1===e.type&&this._onError(e.reason)}_onError(e){this._controller.error(e),this._rejectReady(e),this._port.close()}_resetReady(){this._readyPromise=new Promise(((e,t)=>{this._readyResolve=e,this._readyReject=t})),this._readyPending=!0}_resolveReady(){this._readyResolve(),this._readyPending=!1}_rejectReady(e){this._readyPending||this._resetReady(),this._readyPromise.catch((()=>{})),this._readyReject(e),this._readyPending=!1}}class RemoteWritableStream{constructor(e){const t=new MessageChannel;this.readablePort=t.port1,this.writable=new e(new MessagePortSink(t.port2))}}
|
@ -0,0 +1 @@
|
||||
import{errors}from"../util.js";const{INVALID:INVALID,GONE:GONE,MISMATCH:MISMATCH,MOD_ERR:MOD_ERR,SYNTAX:SYNTAX,ABORT:ABORT}=errors;function setupTxErrorHandler(e,t){e.onerror=()=>t(e.error),e.onabort=()=>t(e.error||new DOMException(...ABORT))}class Sink{constructor(e,t,i,s){this.db=e,this.id=t,this.size=i,this.position=0,this.file=s}write(e){if("object"==typeof e)if("write"===e.type){if(Number.isInteger(e.position)&&e.position>=0&&(this.size<e.position&&(this.file=new File([this.file,new ArrayBuffer(e.position-this.size)],this.file.name,this.file)),this.position=e.position),!("data"in e))throw new DOMException(...SYNTAX("write requires a data argument"));e=e.data}else{if("seek"===e.type){if(Number.isInteger(e.position)&&e.position>=0){if(this.size<e.position)throw new DOMException(...INVALID);return void(this.position=e.position)}throw new DOMException(...SYNTAX("seek requires a position argument"))}if("truncate"===e.type){if(Number.isInteger(e.size)&&e.size>=0){let t=this.file;return t=e.size<this.size?new File([t.slice(0,e.size)],t.name,t):new File([t,new Uint8Array(e.size-this.size)],t.name,t),this.size=t.size,this.position>t.size&&(this.position=t.size),void(this.file=t)}throw new DOMException(...SYNTAX("truncate requires a size argument"))}}e=new Blob([e]);let t=this.file;const i=t.slice(0,this.position),s=t.slice(this.position+e.size);let n=this.position-i.size;n<0&&(n=0),t=new File([i,new Uint8Array(n),e,s],t.name),this.size=t.size,this.position+=e.size,this.file=t}close(){return new Promise(((e,t)=>{const[i,s]=store(this.db);s.get(this.id).onsuccess=e=>{e.target.result?s.put(this.file,this.id):t(new DOMException(...GONE))},i.oncomplete=()=>e(),i.onerror=t,i.onabort=t}))}}class FileHandle{constructor(e,t,i){this._db=e,this._id=t,this.name=i,this.kind="file",this.readable=!0,this.writable=!0}async isSameEntry(e){return this._id===e._id}async getFile(){const e=await new Promise(((e,t)=>{const i=store(this._db)[1].get(this._id);i.onsuccess=t=>e(t.target.result),i.onerror=e=>t(e.target.error)}));if(!e)throw new DOMException(...GONE);return e}async createWritable(e){let t=await this.getFile();return t=e.keepExistingData?t:new File([],this.name),new Sink(this._db,this._id,t.size,t)}}function store(e){const t=e.transaction("entries","readwrite",{durability:"relaxed"});return[t,t.objectStore("entries")]}function rimraf(e,t,i=!0){const{source:s,result:n}=e.target;for(const[e,r]of Object.values(t||n))r?s.delete(e):i?(s.get(e).onsuccess=rimraf,s.delete(e)):s.get(e).onsuccess=t=>{0!==Object.keys(t.target.result).length?t.target.transaction.abort():s.delete(e)}}class FolderHandle{constructor(e,t,i){this._db=e,this._id=t,this.kind="directory",this.name=i,this.readable=!0,this.writable=!0}async*entries(){const e=store(this._db)[1].get(this._id);await new Promise(((t,i)=>{e.onsuccess=()=>t(),e.onerror=()=>i(e.error)}));const t=e.result;if(!t)throw new DOMException(...GONE);for(const[e,[i,s]]of Object.entries(t))yield[e,s?new FileHandle(this._db,i,e):new FolderHandle(this._db,i,e)]}isSameEntry(e){return this._id===e._id}getDirectoryHandle(e,t){return new Promise(((i,s)=>{const n=store(this._db)[1],r=n.get(this._id);r.onsuccess=()=>{const o=r.result,c=o[e];c?c[1]?s(new DOMException(...MISMATCH)):i(new FolderHandle(this._db,c[0],e)):t.create?n.add({}).onsuccess=t=>{const s=t.target.result;o[e]=[s,!1],n.put(o,this._id).onsuccess=()=>i(new FolderHandle(this._db,s,e))}:s(new DOMException(...GONE))}}))}getFileHandle(e,t){return new Promise(((i,s)=>{const n=store(this._db)[1],r=n.get(this._id);r.onsuccess=()=>{const o=r.result,c=o[e];if(c&&c[1]&&i(new FileHandle(this._db,c[0],e)),c&&!c[1]&&s(new DOMException(...MISMATCH)),c||t.create||s(new DOMException(...GONE)),!c&&t.create){const t=n.put(new File([],e));t.onsuccess=()=>{const s=t.result;o[e]=[s,!0];n.put(o,this._id).onsuccess=()=>{i(new FileHandle(this._db,s,e))}}}}}))}async removeEntry(e,t){return new Promise(((i,s)=>{const[n,r]=store(this._db),o=r.get(this._id);o.onsuccess=i=>{const n=o.result,c={_:n[e]};if(!c._)return s(new DOMException(...GONE));delete n[e],r.put(n,this._id),rimraf(i,c,!!t.recursive)},n.oncomplete=i,n.onerror=s,n.onabort=()=>{s(new DOMException(...MOD_ERR))}}))}}export default(e={persistent:!1})=>new Promise((e=>{const t=indexedDB.open("fileSystem");t.onupgradeneeded=()=>{const e=t.result;e.createObjectStore("entries",{autoIncrement:!0}).transaction.oncomplete=t=>{e.transaction("entries","readwrite").objectStore("entries").add({})}},t.onsuccess=()=>{e(new FolderHandle(t.result,1,""))}}));
|
@ -0,0 +1 @@
|
||||
import{errors}from"../util.js";const{GONE:GONE,MISMATCH:MISMATCH,SYNTAX:SYNTAX,DISALLOWED:DISALLOWED}=errors;export class FileHandle{constructor(e,t){this.name=e.name,this.kind="file",this._deleted=!1,this._root=t,this._entry=e,this.writable=!1,this.readable=!0}async getFile(){const e=await fetch(`https://cdn.jsdelivr.net/${this._root}/${this.name}`),t=await e.blob();return new File([t],this.name,{type:t.type,lastModified:this._entry.time})}async createWritable(){throw new DOMException(...DISALLOWED)}async isSameEntry(e){return this===e}}function toDic(e,t){const n={};for(const i of e)i.time=+new Date(i.time),"file"===i.type?n[i.name]=new FileHandle(i,t):n[i.name]=new FolderHandle(i.files,`${t}/${i.name}`,i.name);return n}export class FolderHandle{constructor(e,t,n=""){this.name=n,this.kind="directory",this._deleted=!1,this._entries=toDic(e,t),this.writable=!1,this.readable=!0}async*entries(){yield*Object.entries(this._entries)}async isSameEntry(e){return this===e}async getDirectoryHandle(e,t){if(this._deleted)throw new DOMException(...GONE);const n=this._entries[e];if(n){if(n instanceof FileHandle)throw new DOMException(...MISMATCH);return n}throw t.create?new DOMException(...DISALLOWED):new DOMException(...GONE)}async getFileHandle(e,t){const n=this._entries[e],i=n instanceof FileHandle;if(n&&i)return n;if(n&&!i)throw new DOMException(...MISMATCH);if(!n&&!t.create)throw new DOMException(...GONE);if(!n&&t.create)throw new DOMException(...DISALLOWED)}async removeEntry(e,t){throw new DOMException(...DISALLOWED)}}export default async e=>{const t=await fetch(`https://data.jsdelivr.com/v1/package/${e}`),{files:n}=await t.json();return new FolderHandle(n,e)};
|
@ -0,0 +1 @@
|
||||
import{errors}from"../util.js";import config from"../config.js";const{File:File,Blob:Blob,DOMException:DOMException}=config,{INVALID:INVALID,GONE:GONE,MISMATCH:MISMATCH,MOD_ERR:MOD_ERR,SYNTAX:SYNTAX,SECURITY:SECURITY,DISALLOWED:DISALLOWED}=errors;export class Sink{constructor(e,i){this.fileHandle=e,this.file=i,this.size=i.size,this.position=0}write(e){let i=this.file;if("object"==typeof e)if("write"===e.type){if(Number.isInteger(e.position)&&e.position>=0&&(this.position=e.position,this.size<e.position&&(this.file=new File([this.file,new ArrayBuffer(e.position-this.size)],this.file.name,this.file))),!("data"in e))throw new DOMException(...SYNTAX("write requires a data argument"));e=e.data}else{if("seek"===e.type){if(Number.isInteger(e.position)&&e.position>=0){if(this.size<e.position)throw new DOMException(...INVALID);return void(this.position=e.position)}throw new DOMException(...SYNTAX("seek requires a position argument"))}if("truncate"===e.type){if(Number.isInteger(e.size)&&e.size>=0)return i=e.size<this.size?new File([i.slice(0,e.size)],i.name,i):new File([i,new Uint8Array(e.size-this.size)],i.name),this.size=i.size,this.position>i.size&&(this.position=i.size),void(this.file=i);throw new DOMException(...SYNTAX("truncate requires a size argument"))}}e=new Blob([e]);let t=this.file;const s=t.slice(0,this.position),n=t.slice(this.position+e.size);let o=this.position-s.size;o<0&&(o=0),t=new File([s,new Uint8Array(o),e,n],t.name),this.size=t.size,this.position+=e.size,this.file=t}close(){if(this.fileHandle._deleted)throw new DOMException(...GONE);this.fileHandle._file=this.file,this.file=this.position=this.size=null,this.fileHandle.onclose&&this.fileHandle.onclose(this.fileHandle)}}export class FileHandle{constructor(e="",i=new File([],e),t=!0){this._file=i,this.name=e,this.kind="file",this._deleted=!1,this.writable=t,this.readable=!0}async getFile(){if(this._deleted)throw new DOMException(...GONE);return this._file}async createWritable(e){if(!this.writable)throw new DOMException(...DISALLOWED);if(this._deleted)throw new DOMException(...GONE);const i=e.keepExistingData?await this.getFile():new File([],this.name);return new Sink(this,i)}async isSameEntry(e){return this===e}async _destroy(){this._deleted=!0,this._file=null}}export class FolderHandle{constructor(e,i=!0){this.name=e,this.kind="directory",this._deleted=!1,this._entries={},this.writable=i,this.readable=!0}async*entries(){if(this._deleted)throw new DOMException(...GONE);yield*Object.entries(this._entries)}async isSameEntry(e){return this===e}async getDirectoryHandle(e,i){if(this._deleted)throw new DOMException(...GONE);const t=this._entries[e];if(t){if(t instanceof FileHandle)throw new DOMException(...MISMATCH);return t}if(i.create)return this._entries[e]=new FolderHandle(e);throw new DOMException(...GONE)}async getFileHandle(e,i){const t=this._entries[e],s=t instanceof FileHandle;if(t&&s)return t;if(t&&!s)throw new DOMException(...MISMATCH);if(!t&&!i.create)throw new DOMException(...GONE);return!t&&i.create?this._entries[e]=new FileHandle(e):void 0}async removeEntry(e,i){const t=this._entries[e];if(!t)throw new DOMException(...GONE);await t._destroy(i.recursive),delete this._entries[e]}async _destroy(e){for(let i of Object.values(this._entries)){if(!e)throw new DOMException(...MOD_ERR);await i._destroy(e)}this._entries={},this._deleted=!0}}const fs=new FolderHandle("");export default()=>fs;
|
@ -0,0 +1 @@
|
||||
import fs from"node:fs/promises";import{join}from"node:path";import{errors}from"../util.js";import config from"../config.js";const{DOMException:DOMException}=config,{INVALID:INVALID,GONE:GONE,MISMATCH:MISMATCH,MOD_ERR:MOD_ERR,SYNTAX:SYNTAX}=errors;function isBlob(t){return t&&"object"==typeof t&&"function"==typeof t.constructor&&("function"==typeof t.stream||"function"==typeof t.arrayBuffer)&&/^(Blob|File)$/.test(t[Symbol.toStringTag])}export class Sink{constructor(t,i){this._fileHandle=t,this._size=i,this._position=0}async abort(){await this._fileHandle.close()}async write(t){if("object"==typeof t)if("write"===t.type){if(Number.isInteger(t.position)&&t.position>=0&&(this._position=t.position),!("data"in t))throw await this._fileHandle.close(),new DOMException(...SYNTAX("write requires a data argument"));t=t.data}else{if("seek"===t.type){if(Number.isInteger(t.position)&&t.position>=0){if(this._size<t.position)throw new DOMException(...INVALID);return void(this._position=t.position)}throw await this._fileHandle.close(),new DOMException(...SYNTAX("seek requires a position argument"))}if("truncate"===t.type){if(Number.isInteger(t.size)&&t.size>=0)return await this._fileHandle.truncate(t.size),this._size=t.size,void(this._position>this._size&&(this._position=this._size));throw await this._fileHandle.close(),new DOMException(...SYNTAX("truncate requires a size argument"))}}if(t instanceof ArrayBuffer)t=new Uint8Array(t);else if("string"==typeof t)t=Buffer.from(t);else if(isBlob(t)){for await(const i of t.stream()){const t=await this._fileHandle.writev([i],this._position);this._position+=t.bytesWritten,this._size+=t.bytesWritten}return}const i=await this._fileHandle.writev([t],this._position);this._position+=i.bytesWritten,this._size+=i.bytesWritten}async close(){await this._fileHandle.close()}}export class FileHandle{constructor(t,i){this._path=t,this.name=i,this.kind="file"}async getFile(){await fs.stat(this._path).catch((t=>{if("ENOENT"===t.code)throw new DOMException(...GONE)}));const{fileFrom:t}=await import("fetch-blob/from.js");return t(this._path)}async isSameEntry(t){return this._path===this._getPath.apply(t)}_getPath(){return this._path}async createWritable(t){const i=await fs.open(this._path,t.keepExistingData?"r+":"w+").catch((t=>{if("ENOENT"===t.code)throw new DOMException(...GONE);throw t})),{size:e}=await i.stat();return new Sink(i,e)}}export class FolderHandle{_path="";constructor(t="",i=""){this.name=i,this.kind="directory",this._path=t}async isSameEntry(t){return this._path===t._path}async*entries(){const t=this._path,i=await fs.readdir(t).catch((t=>{if("ENOENT"===t.code)throw new DOMException(...GONE);throw t}));for(let e of i){const i=join(t,e),o=await fs.lstat(i);o.isFile()?yield[e,new FileHandle(i,e)]:o.isDirectory()&&(yield[e,new FolderHandle(i,e)])}}async getDirectoryHandle(t,i){const e=join(this._path,t),o=await fs.lstat(e).catch((t=>{if("ENOENT"!==t.code)throw t})),s=o?.isDirectory();if(o&&s)return new FolderHandle(e,t);if(o&&!s)throw new DOMException(...MISMATCH);if(!i.create)throw new DOMException(...GONE);return await fs.mkdir(e),new FolderHandle(e,t)}async getFileHandle(t,i){const e=join(this._path,t),o=await fs.lstat(e).catch((t=>{if("ENOENT"!==t.code)throw t})),s=o?.isFile();if(o&&s)return new FileHandle(e,t);if(o&&!s)throw new DOMException(...MISMATCH);if(!i.create)throw new DOMException(...GONE);return await(await fs.open(e,"w")).close(),new FileHandle(e,t)}async queryPermission(){return"granted"}async removeEntry(t,i){const e=join(this._path,t);(await fs.lstat(e).catch((t=>{if("ENOENT"===t.code)throw new DOMException(...GONE);throw t}))).isDirectory()?i.recursive?await fs.rm(e,{recursive:!0}).catch((t=>{if("ENOTEMPTY"===t.code)throw new DOMException(...MOD_ERR);throw t})):await fs.rmdir(e).catch((t=>{if("ENOTEMPTY"===t.code)throw new DOMException(...MOD_ERR);throw t})):await fs.unlink(e)}}export default t=>new FolderHandle(t);
|
@ -0,0 +1 @@
|
||||
import{errors}from"../util.js";const{DISALLOWED:DISALLOWED}=errors;class Sink{constructor(e,i){this.writer=e,this.fileEntry=i}async write(e){if("object"==typeof e)if("write"===e.type){if(Number.isInteger(e.position)&&e.position>=0&&(this.writer.seek(e.position),this.writer.position!==e.position&&(await new Promise(((i,t)=>{this.writer.onwriteend=i,this.writer.onerror=t,this.writer.truncate(e.position)})),this.writer.seek(e.position))),!("data"in e))throw new DOMException("Failed to execute 'write' on 'UnderlyingSinkBase': Invalid params passed. write requires a data argument","SyntaxError");e=e.data}else{if("seek"===e.type){if(Number.isInteger(e.position)&&e.position>=0){if(this.writer.seek(e.position),this.writer.position!==e.position)throw new DOMException("seeking position failed","InvalidStateError");return}throw new DOMException("Failed to execute 'write' on 'UnderlyingSinkBase': Invalid params passed. seek requires a position argument","SyntaxError")}if("truncate"===e.type)return new Promise((i=>{if(!(Number.isInteger(e.size)&&e.size>=0))throw new DOMException("Failed to execute 'write' on 'UnderlyingSinkBase': Invalid params passed. truncate requires a size argument","SyntaxError");this.writer.onwriteend=e=>i(),this.writer.truncate(e.size)}))}await new Promise(((i,t)=>{this.writer.onwriteend=i,this.writer.onerror=t,this.writer.write(new Blob([e]))}))}close(){return new Promise(this.fileEntry.file.bind(this.fileEntry))}}export class FileHandle{constructor(e,i=!0){this.file=e,this.kind="file",this.writable=i,this.readable=!0}get name(){return this.file.name}isSameEntry(e){return this.file.toURL()===e.file.toURL()}getFile(){return new Promise(this.file.file.bind(this.file))}createWritable(e){if(!this.writable)throw new DOMException(...DISALLOWED);return new Promise(((i,t)=>this.file.createWriter((t=>{!1===e.keepExistingData?(t.onwriteend=e=>i(new Sink(t,this.file)),t.truncate(0)):i(new Sink(t,this.file))}),t)))}}export class FolderHandle{constructor(e,i=!0){this.dir=e,this.writable=i,this.readable=!0,this.kind="directory",this.name=e.name}isSameEntry(e){return this.dir.fullPath===e.dir.fullPath}async*entries(){const e=this.dir.createReader(),i=await new Promise(e.readEntries.bind(e));for(const e of i)yield[e.name,e.isFile?new FileHandle(e,this.writable):new FolderHandle(e,this.writable)]}getDirectoryHandle(e,i){return new Promise(((t,r)=>{this.dir.getDirectory(e,i,(e=>{t(new FolderHandle(e))}),r)}))}getFileHandle(e,i){return new Promise(((t,r)=>this.dir.getFile(e,i,(e=>t(new FileHandle(e))),r)))}async removeEntry(e,i){const t=await this.getDirectoryHandle(e,{create:!1}).catch((i=>"TypeMismatchError"===i.name?this.getFileHandle(e,{create:!1}):i));if(t instanceof Error)throw t;return new Promise(((e,r)=>{t instanceof FolderHandle?i.recursive?t.dir.removeRecursively((()=>e()),r):t.dir.remove((()=>e()),r):t.file&&t.file.remove((()=>e()),r)}))}}export default(e={})=>new Promise(((i,t)=>window.webkitRequestFileSystem(e._persistent,0,(e=>i(new FolderHandle(e.root))),t)));
|
@ -0,0 +1 @@
|
||||
const config={ReadableStream:globalThis.ReadableStream,WritableStream:globalThis.WritableStream,TransformStream:globalThis.TransformStream,DOMException:globalThis.DOMException,Blob:globalThis.Blob,File:globalThis.File};export default config;
|
@ -0,0 +1 @@
|
||||
import showDirectoryPicker from"./showDirectoryPicker.js";import showOpenFilePicker from"./showOpenFilePicker.js";import showSaveFilePicker from"./showSaveFilePicker.js";import getOriginPrivateDirectory from"./getOriginPrivateDirectory.js";import FileSystemWritableFileStream from"./FileSystemWritableFileStream.js";import FileSystemDirectoryHandle from"./FileSystemDirectoryHandle.js";import FileSystemFileHandle from"./FileSystemFileHandle.js";import FileSystemHandle from"./FileSystemHandle.js";export{FileSystemDirectoryHandle,FileSystemFileHandle,FileSystemHandle,FileSystemWritableFileStream,getOriginPrivateDirectory,showDirectoryPicker,showOpenFilePicker,showSaveFilePicker};
|
@ -0,0 +1 @@
|
||||
async function getOriginPrivateDirectory(e,t={}){if(!e)return globalThis.navigator?.storage?.getDirectory()||globalThis.getOriginPrivateDirectory();const{FileSystemDirectoryHandle:i}=await import("./FileSystemDirectoryHandle.js"),r=await e;return new i(await(r.default?r.default(t):r(t)))}globalThis.DataTransferItem&&!DataTransferItem.prototype.getAsFileSystemHandle&&(DataTransferItem.prototype.getAsFileSystemHandle=async function(){const e=this.webkitGetAsEntry(),[{FileHandle:t,FolderHandle:i},{FileSystemDirectoryHandle:r},{FileSystemFileHandle:a}]=await Promise.all([import("./adapters/sandbox.js"),import("./FileSystemDirectoryHandle.js"),import("./FileSystemFileHandle.js")]);return e.isFile?new a(new t(e,!1)):new r(new i(e,!1))});export default getOriginPrivateDirectory;
|
@ -0,0 +1 @@
|
||||
const native=globalThis.showDirectoryPicker;async function showDirectoryPicker(e={}){if(native&&!e._preferPolyfill)return native(e);const t=document.createElement("input");t.type="file",t.webkitdirectory=!0,t.multiple=!0,t.style.position="fixed",t.style.top="-100000px",t.style.left="-100000px",document.body.appendChild(t);const i=import("./util.js");return await new Promise((e=>{t.addEventListener("change",e),t.click()})),i.then((e=>e.getDirHandlesFromInput(t)))}export default showDirectoryPicker;export{showDirectoryPicker};
|
@ -0,0 +1 @@
|
||||
const def={accepts:[]},native=globalThis.showOpenFilePicker;async function showOpenFilePicker(e={}){const t={...def,...e};if(native&&!e._preferPolyfill)return native(t);const i=document.createElement("input");i.type="file",i.multiple=t.multiple,i.accept=(t.accepts||[]).map((e=>[...(e.extensions||[]).map((e=>"."+e)),...e.mimeTypes||[]])).flat().join(","),Object.assign(i.style,{position:"fixed",top:"-100000px",left:"-100000px"}),document.body.appendChild(i);const n=import("./util.js");return await new Promise((e=>{i.addEventListener("change",e,{once:!0}),i.click()})),i.remove(),n.then((e=>e.getFileHandlesFromInput(i)))}export default showOpenFilePicker;export{showOpenFilePicker};
|
@ -0,0 +1 @@
|
||||
const native=globalThis.showSaveFilePicker;async function showSaveFilePicker(e={}){if(native&&!e._preferPolyfill)return native(e);e._name&&(console.warn("deprecated _name, spec now have `suggestedName`"),e.suggestedName=e._name);const{FileSystemFileHandle:a}=await import("./FileSystemFileHandle.js"),{FileHandle:i}=await import("./adapters/downloader.js");return new a(new i(e.suggestedName))}export default showSaveFilePicker;export{showSaveFilePicker};
|
@ -0,0 +1 @@
|
||||
export const errors={INVALID:["seeking position failed.","InvalidStateError"],GONE:["A requested file or directory could not be found at the time an operation was processed.","NotFoundError"],MISMATCH:["The path supplied exists, but was not an entry of requested type.","TypeMismatchError"],MOD_ERR:["The object can not be modified in this way.","InvalidModificationError"],SYNTAX:e=>[`Failed to execute 'write' on 'UnderlyingSinkBase': Invalid params passed. ${e}`,"SyntaxError"],SECURITY:["It was determined that certain files are unsafe for access within a Web application, or that too many calls are being made on file resources.","SecurityError"],DISALLOWED:["The request is not allowed by the user agent or the platform in the current context.","NotAllowedError"]};export const config={writable:globalThis.WritableStream};export async function fromDataTransfer(e){console.warn("deprecated fromDataTransfer - use `dt.items[0].getAsFileSystemHandle()` instead");const[t,r,a]=await Promise.all([import("./adapters/memory.js"),import("./adapters/sandbox.js"),import("./FileSystemDirectoryHandle.js")]),n=new t.FolderHandle("",!1);return n._entries=e.map((e=>e.isFile?new r.FileHandle(e,!1):new r.FolderHandle(e,!1))),new a.FileSystemDirectoryHandle(n)}export async function getDirHandlesFromInput(e){const{FolderHandle:t,FileHandle:r}=await import("./adapters/memory.js"),{FileSystemDirectoryHandle:a}=await import("./FileSystemDirectoryHandle.js"),n=Array.from(e.files),i=n[0].webkitRelativePath.split("/",1)[0],o=new t(i,!1);return n.forEach((e=>{const a=e.webkitRelativePath.split("/");a.shift();const n=a.pop();a.reduce(((e,r)=>(e._entries[r]||(e._entries[r]=new t(r,!1)),e._entries[r])),o)._entries[n]=new r(e.name,e,!1)})),new a(o)}export async function getFileHandlesFromInput(e){const{FileHandle:t}=await import("./adapters/memory.js"),{FileSystemFileHandle:r}=await import("./FileSystemFileHandle.js");return Array.from(e.files).map((e=>new r(new t(e.name,e,!1))))}
|
1
core/static/core/js/native-file-system-adapter/sw.js
Normal file
1
core/static/core/js/native-file-system-adapter/sw.js
Normal file
@ -0,0 +1 @@
|
||||
const WRITE=0,PULL=0,ERROR=1,ABORT=1,CLOSE=2,PING=3;class MessagePortSource{controller;constructor(e){this.port=e,this.port.onmessage=e=>this.onMessage(e.data)}start(e){this.controller=e}pull(){this.port.postMessage({type:0})}cancel(e){this.port.postMessage({type:1,reason:e.message}),this.port.close()}onMessage(e){0===e.type&&this.controller.enqueue(e.chunk),1===e.type&&(this.controller.error(e.reason),this.port.close()),2===e.type&&(this.controller.close(),this.port.close())}}self.addEventListener("install",(()=>{self.skipWaiting()})),self.addEventListener("activate",(e=>{e.waitUntil(self.clients.claim())}));const map=new Map;globalThis.addEventListener("message",(e=>{const t=e.data;t.url&&t.readablePort&&(t.rs=new ReadableStream(new MessagePortSource(e.data.readablePort),new CountQueuingStrategy({highWaterMark:4})),map.set(t.url,t))})),globalThis.addEventListener("fetch",(e=>{const t=e.request.url,s=map.get(t);if(!s)return null;map.delete(t),e.respondWith(new Response(s.rs,{headers:s.headers}))}));
|
@ -21,9 +21,9 @@
|
||||
overflow: auto;
|
||||
max-width: 100%;
|
||||
font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console",
|
||||
"Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono",
|
||||
"Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier,
|
||||
monospace;
|
||||
"Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono",
|
||||
"Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier,
|
||||
monospace;
|
||||
font-size: 14px;
|
||||
tab-size: 4;
|
||||
border-radius: 4px;
|
||||
|
@ -1,5 +1,7 @@
|
||||
@import "colors";
|
||||
|
||||
nav.navbar {
|
||||
background-color: hsl(203, 75%, 40%);
|
||||
background-color: $primary-dark-color;
|
||||
margin: 1em;
|
||||
color: white;
|
||||
border-radius: 0.6em;
|
||||
@ -43,7 +45,7 @@ nav.navbar {
|
||||
justify-content: center;
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
|
||||
> .menu,
|
||||
> .link {
|
||||
box-sizing: border-box;
|
||||
@ -146,5 +148,5 @@ nav.navbar {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
core/static/core/pagination.scss
Normal file
37
core/static/core/pagination.scss
Normal file
@ -0,0 +1,37 @@
|
||||
@import "colors";
|
||||
|
||||
.pagination {
|
||||
text-align: center;
|
||||
gap: 10px;
|
||||
|
||||
button {
|
||||
background-color: $secondary-neutral-light-color;
|
||||
min-width: 37px;
|
||||
|
||||
&:hover {
|
||||
background-color: darken($secondary-neutral-light-color, 10%);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
color: #fff;
|
||||
background-color: darken($secondary-neutral-light-color, 5%);
|
||||
}
|
||||
|
||||
&.active,
|
||||
&.active:hover {
|
||||
background-color: $primary-neutral-color;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&:first-of-type,
|
||||
&:last-of-type {
|
||||
// previous and next buttons
|
||||
&:disabled {
|
||||
// Hide the arrows when they are disabled, without
|
||||
// changing the layout of the navigation
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +1,9 @@
|
||||
$first-color: hsl(220, 100%, 50%);
|
||||
$second-color: hsl(48, 100%, 67%);
|
||||
$primary-color: hsl(219.9, 53.7%, 50%);
|
||||
$secondary-color: hsl(204, 64%, 44%);
|
||||
$primary-color-text: hsl(0, 0%, 100%);
|
||||
$secondary-color-text: hsla(0, 0%, 0%, 0.87);
|
||||
|
||||
$primary-light-color: hsl(219.8, 46.4%, 64.9%);
|
||||
$primary-dark-color: hsl(203, 75%, 40%);
|
||||
|
||||
$secondary-light-color: hsl(40, 68%, 65%);
|
||||
$secondary-dark-color: hsl(40, 68%, 35%);
|
||||
|
||||
$primary-neutral-color: hsl(219.6, 20.8%, 50%);
|
||||
$primary-neutral-light-color: hsl(0, 0%, 94%);
|
||||
$primary-neutral-dark-color: hsl(210, 29%, 29%);
|
||||
|
||||
$secondary-neutral-color: hsl(204, 64%, 44%);
|
||||
$secondary-neutral-light-color: hsl(0, 0%, 91%);
|
||||
$secondary-neutral-dark-color: hsl(40, 57.6%, 17%);
|
||||
|
||||
$white-color: hsl(219.6, 20.8%, 98%);
|
||||
$black-color: hsl(0, 0%, 17%);
|
||||
|
||||
$faceblue: hsl(221, 44%, 41%);
|
||||
$twitblue: hsl(206, 82%, 63%);
|
||||
|
||||
$shadow-color: rgb(223, 223, 223);
|
||||
|
||||
$background-button-color: hsl(0, 0%, 95%);
|
||||
@import "colors";
|
||||
|
||||
/*--------------------------MEDIA QUERY HELPERS------------------------*/
|
||||
$small-devices: 576px;
|
||||
$medium-devices: 768px;
|
||||
$large-devices: 992px;
|
||||
$extra-large-devices: 1200px;
|
||||
|
||||
/*--------------------------------GENERAL------------------------------*/
|
||||
|
||||
@ -43,17 +13,6 @@ body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
button:disabled,
|
||||
button:disabled:hover {
|
||||
color: #fff;
|
||||
background-color: #6c757d;
|
||||
}
|
||||
|
||||
button.active,
|
||||
button.active:hover {
|
||||
color: #fff;
|
||||
background-color: $secondary-color;
|
||||
}
|
||||
|
||||
a.button,
|
||||
button,
|
||||
@ -170,7 +129,7 @@ a:not(.button) {
|
||||
|
||||
.shadow {
|
||||
box-shadow: rgba(60, 64, 67, 0.3) 0 1px 3px 0,
|
||||
rgba(60, 64, 67, 0.15) 0 4px 8px 3px;
|
||||
rgba(60, 64, 67, 0.15) 0 4px 8px 3px;
|
||||
}
|
||||
|
||||
.w_big {
|
||||
@ -246,7 +205,7 @@ a:not(.button) {
|
||||
#page {
|
||||
width: 90%;
|
||||
margin: 20px auto 0;
|
||||
/*---------------------------------NAV---------------------------------*/
|
||||
/*---------------------------------NAV---------------------------------*/
|
||||
|
||||
.btn {
|
||||
font-size: 15px;
|
||||
@ -278,7 +237,7 @@ a:not(.button) {
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------CONTENT------------------------------*/
|
||||
/*--------------------------------CONTENT------------------------------*/
|
||||
#quick_notif {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
@ -357,7 +316,7 @@ a:not(.button) {
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------NEWS--------------------------------*/
|
||||
/*---------------------------------NEWS--------------------------------*/
|
||||
#news {
|
||||
display: flex;
|
||||
|
||||
@ -385,11 +344,11 @@ a:not(.button) {
|
||||
background: $second-color;
|
||||
box-shadow: $shadow-color 1px 1px 1px;
|
||||
padding: 0.4em;
|
||||
margin: 0em 0em 0.5em 0em;
|
||||
margin: 0 0 0.5em 0;
|
||||
text-transform: uppercase;
|
||||
font-size: 1.1em;
|
||||
&:not(:first-of-type) {
|
||||
margin: 2em 0em 1em 0em;
|
||||
margin: 2em 0 1em 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -400,7 +359,7 @@ a:not(.button) {
|
||||
}
|
||||
}
|
||||
|
||||
/* AGENDA/BIRTHDAYS */
|
||||
/* AGENDA/BIRTHDAYS */
|
||||
#agenda,
|
||||
#birthdays {
|
||||
display: block;
|
||||
@ -410,7 +369,7 @@ a:not(.button) {
|
||||
margin-bottom: 1em;
|
||||
#agenda_title,
|
||||
#birthdays_title {
|
||||
margin: 0em;
|
||||
margin: 0;
|
||||
border-radius: 5px 5px 0 0;
|
||||
box-shadow: $shadow-color 1px 1px 1px;
|
||||
padding: 0.5em;
|
||||
@ -444,7 +403,7 @@ a:not(.button) {
|
||||
}
|
||||
}
|
||||
ul.birthdays_year {
|
||||
margin: 0em;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
font-weight: bold;
|
||||
> li {
|
||||
@ -454,7 +413,7 @@ a:not(.button) {
|
||||
}
|
||||
}
|
||||
ul {
|
||||
margin: 0em;
|
||||
margin: 0;
|
||||
margin-left: 1em;
|
||||
list-style-type: square;
|
||||
list-style-position: inside;
|
||||
@ -463,9 +422,9 @@ a:not(.button) {
|
||||
}
|
||||
}
|
||||
}
|
||||
/* END AGENDA/BIRTHDAYS */
|
||||
/* END AGENDA/BIRTHDAYS */
|
||||
|
||||
/* EVENTS TODAY AND NEXT FEW DAYS */
|
||||
/* EVENTS TODAY AND NEXT FEW DAYS */
|
||||
.news_events_group {
|
||||
box-shadow: $shadow-color 1px 1px 1px;
|
||||
margin-left: 1em;
|
||||
@ -516,14 +475,14 @@ a:not(.button) {
|
||||
float: left;
|
||||
min-width: 7em;
|
||||
max-width: 9em;
|
||||
margin: 0em;
|
||||
margin: 0;
|
||||
margin-right: 1em;
|
||||
margin-top: 0.8em;
|
||||
img {
|
||||
max-height: 6em;
|
||||
max-width: 8em;
|
||||
display: block;
|
||||
margin: 0em auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
.news_date {
|
||||
@ -544,15 +503,15 @@ a:not(.button) {
|
||||
}
|
||||
}
|
||||
}
|
||||
/* END EVENTS TODAY AND NEXT FEW DAYS */
|
||||
/* END EVENTS TODAY AND NEXT FEW DAYS */
|
||||
|
||||
/* COMING SOON */
|
||||
/* COMING SOON */
|
||||
.news_coming_soon {
|
||||
display: list-item;
|
||||
list-style-type: square;
|
||||
list-style-position: inside;
|
||||
margin-left: 1em;
|
||||
padding-left: 0em;
|
||||
padding-left: 0;
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
@ -561,35 +520,35 @@ a:not(.button) {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
/* END COMING SOON */
|
||||
/* END COMING SOON */
|
||||
|
||||
/* NOTICES */
|
||||
/* NOTICES */
|
||||
.news_notice {
|
||||
margin: 0em 0em 1em 1em;
|
||||
margin: 0 0 1em 1em;
|
||||
padding: 0.4em;
|
||||
padding-left: 1em;
|
||||
background: $secondary-neutral-light-color;
|
||||
box-shadow: $shadow-color 0 0 2px;
|
||||
border-radius: 18px 5px 18px 5px;
|
||||
h4 {
|
||||
margin: 0em;
|
||||
margin: 0;
|
||||
}
|
||||
.news_content {
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
/* END NOTICES */
|
||||
/* END NOTICES */
|
||||
|
||||
/* CALLS */
|
||||
/* CALLS */
|
||||
.news_call {
|
||||
margin: 0em 0em 1em 1em;
|
||||
margin: 0 0 1em 1em;
|
||||
padding: 0.4em;
|
||||
padding-left: 1em;
|
||||
background: $secondary-neutral-light-color;
|
||||
border: 1px solid grey;
|
||||
box-shadow: $shadow-color 1px 1px 1px;
|
||||
h4 {
|
||||
margin: 0em;
|
||||
margin: 0;
|
||||
}
|
||||
.news_date {
|
||||
font-size: 0.9em;
|
||||
@ -598,7 +557,7 @@ a:not(.button) {
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
/* END CALLS */
|
||||
/* END CALLS */
|
||||
|
||||
.news_empty {
|
||||
margin-left: 1em;
|
||||
@ -631,12 +590,12 @@ a:not(.button) {
|
||||
width: 19%;
|
||||
float: left;
|
||||
min-width: 15em;
|
||||
margin: 0em;
|
||||
margin: 0;
|
||||
img {
|
||||
max-height: 15em;
|
||||
max-width: 12em;
|
||||
display: block;
|
||||
margin: 0em auto;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
@ -646,7 +605,6 @@ a:not(.button) {
|
||||
padding: 0.5em 1em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 1.2em;
|
||||
border-radius: 2px;
|
||||
float: right;
|
||||
@ -978,7 +936,7 @@ table {
|
||||
-moz-border-radius: 5px;
|
||||
overflow: hidden;
|
||||
box-shadow: rgba(60, 64, 67, 0.3) 0 1px 3px 0,
|
||||
rgba(60, 64, 67, 0.15) 0 4px 8px 3px;
|
||||
rgba(60, 64, 67, 0.15) 0 4px 8px 3px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
@ -1198,8 +1156,8 @@ u,
|
||||
color: $primary-neutral-dark-color;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0em;
|
||||
padding: 0em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@ -1393,7 +1351,7 @@ footer {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
div {
|
||||
margin: 0.6em 0em;
|
||||
margin: 0.6em 0;
|
||||
color: $white-color;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
@ -1507,514 +1465,3 @@ a.ui-button:active,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------pedagogy-----------------------------------*/
|
||||
|
||||
$pedagogy-blue: #1bb9ea;
|
||||
$pedagogy-orange: #ea7900;
|
||||
$pedagogy-hover-blue: #0e97ce;
|
||||
$pedagogy-light-blue: #caf0ff;
|
||||
$pedagogy-white-text: #f0f0f0;
|
||||
|
||||
.pedagogy {
|
||||
#pagination {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&.star-not-checked {
|
||||
color: #f7f7f7;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
&.star-checked {
|
||||
color: $pedagogy-orange;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&.grade-without-star {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
&.star-not-checked {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
&.star-checked {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $small-devices) {
|
||||
&.grade-without-star {
|
||||
display: block;
|
||||
}
|
||||
&.grade-with-star {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#dynamic_view {
|
||||
font-size: 1.1em;
|
||||
|
||||
overflow-wrap: break-word;
|
||||
|
||||
td {
|
||||
text-align: center;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
#search_form {
|
||||
.search-form-container {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
grid-template-rows: auto auto auto;
|
||||
grid-template-areas:
|
||||
"action-bar action-bar"
|
||||
"search-bar search-bar"
|
||||
"radio-department radio-department"
|
||||
"radio-credit-type radio-semester";
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
grid-area: action-bar;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
grid-area: search-bar;
|
||||
display: grid;
|
||||
grid-template-columns: auto 200px;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas: "search-bar-input search-bar-button";
|
||||
|
||||
@media screen and (max-width: $medium-devices) {
|
||||
grid-template-columns: auto auto;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas: "search-bar-input search-bar-button";
|
||||
}
|
||||
|
||||
@media screen and (max-width: $small-devices) {
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas: "search-bar-input";
|
||||
|
||||
.search-bar-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.search-bar-input {
|
||||
grid-area: search-bar-input;
|
||||
background: $pedagogy-light-blue;
|
||||
}
|
||||
|
||||
.search-bar-button {
|
||||
grid-area: search-bar-button;
|
||||
background: $pedagogy-orange;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.radio-department {
|
||||
grid-area: radio-department;
|
||||
}
|
||||
|
||||
.radio-credit-type {
|
||||
grid-area: radio-credit-type;
|
||||
}
|
||||
|
||||
.radio-semester {
|
||||
grid-area: radio-semester;
|
||||
}
|
||||
|
||||
.radio-guide input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
.radio-guide {
|
||||
margin-top: 10px;
|
||||
color: white;
|
||||
}
|
||||
.radio-guide label {
|
||||
display: inline-block;
|
||||
background-color: $pedagogy-blue;
|
||||
padding: 10px 20px;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.radio-guide input[type="radio"]:checked + label {
|
||||
background-color: $pedagogy-orange;
|
||||
}
|
||||
.radio-guide input[type="checkbox"]:checked + label {
|
||||
background-color: $pedagogy-orange;
|
||||
}
|
||||
.radio-guide label:hover {
|
||||
background-color: $pedagogy-hover-blue;
|
||||
}
|
||||
}
|
||||
|
||||
#uv_detail {
|
||||
color: #062f38;
|
||||
|
||||
.uv-quick-info-container {
|
||||
display: grid;
|
||||
grid-template-columns: 20% 20% 20% 20% auto;
|
||||
grid-template-rows: auto auto;
|
||||
grid-template-areas:
|
||||
"hours-cm hours-td hours-tp hours-te hours-the"
|
||||
"department credit-type semester . .";
|
||||
}
|
||||
|
||||
.department {
|
||||
grid-area: department;
|
||||
}
|
||||
|
||||
.credit-type {
|
||||
grid-area: credit-type;
|
||||
}
|
||||
|
||||
.semester {
|
||||
grid-area: semester;
|
||||
}
|
||||
|
||||
.hours-cm {
|
||||
grid-area: hours-cm;
|
||||
}
|
||||
|
||||
.hours-td {
|
||||
grid-area: hours-td;
|
||||
}
|
||||
|
||||
.hours-tp {
|
||||
grid-area: hours-tp;
|
||||
}
|
||||
|
||||
.hours-te {
|
||||
grid-area: hours-te;
|
||||
}
|
||||
|
||||
.hours-the {
|
||||
grid-area: hours-the;
|
||||
}
|
||||
|
||||
#leave_comment_not_allowed {
|
||||
p {
|
||||
text-align: center;
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
#leave_comment {
|
||||
.leave-comment-grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: 270px auto;
|
||||
grid-template-rows: 100%;
|
||||
grid-template-areas: "stars comment";
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: auto auto;
|
||||
grid-template-areas:
|
||||
"stars"
|
||||
"comment";
|
||||
}
|
||||
}
|
||||
|
||||
.ui-accordion-content {
|
||||
background-color: $white-color;
|
||||
border-color: $pedagogy-orange;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.form-stars {
|
||||
grid-area: stars;
|
||||
}
|
||||
|
||||
.form-comment {
|
||||
grid-area: comment;
|
||||
}
|
||||
|
||||
.ui-accordion-header {
|
||||
background-color: $pedagogy-orange;
|
||||
color: $pedagogy-white-text;
|
||||
clip-path: polygon(0 0%, 0 100%, 30% 100%, 33% 0);
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
clip-path: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-accordion-header-icon {
|
||||
color: $pedagogy-white-text;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.input-stars {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
input[type="submit"] {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.uv-details-container {
|
||||
display: grid;
|
||||
grid-template-columns: 150px 100px auto;
|
||||
grid-template-rows: 156px 1fr;
|
||||
grid-template-areas:
|
||||
"grade grade-stars uv-infos"
|
||||
". . uv-infos";
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
grid-template-columns: 50% 50%;
|
||||
grid-template-rows: auto auto;
|
||||
grid-template-areas:
|
||||
"grade grade-stars"
|
||||
"uv-infos uv-infos";
|
||||
}
|
||||
}
|
||||
|
||||
.grade {
|
||||
grid-area: grade;
|
||||
color: $pedagogy-white-text;
|
||||
background-color: $pedagogy-blue;
|
||||
padding-right: 10px;
|
||||
|
||||
> p {
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.grade-stars {
|
||||
grid-area: grade-stars;
|
||||
color: $pedagogy-white-text;
|
||||
background-color: $pedagogy-blue;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.uv-infos {
|
||||
grid-area: uv-infos;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.comment-container {
|
||||
display: grid;
|
||||
grid-template-columns: 300px auto;
|
||||
grid-template-rows: auto auto auto;
|
||||
grid-template-areas:
|
||||
"grade-block comment"
|
||||
"grade-block info"
|
||||
"comment-end-bar comment-end-bar";
|
||||
margin-bottom: 30px;
|
||||
margin-top: 10px;
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto auto auto auto;
|
||||
grid-template-areas:
|
||||
"grade-block"
|
||||
"comment"
|
||||
"info"
|
||||
"comment-end-bar";
|
||||
}
|
||||
|
||||
.grade-block {
|
||||
grid-area: grade-block;
|
||||
width: 300px;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 150px 150px;
|
||||
grid-template-rows: 156px auto;
|
||||
grid-template-areas:
|
||||
"grade-type grade-stars"
|
||||
"grade-extension grade-extension";
|
||||
grid-gap: 15px;
|
||||
|
||||
clip-path: polygon(0 0, 0 100%, 100% 100%, 100% 30px, 270px 0);
|
||||
align-items: start;
|
||||
|
||||
background-color: $pedagogy-blue;
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
grid-template-columns: 50% auto;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas: "grade-type grade-stars";
|
||||
width: auto;
|
||||
clip-path: none;
|
||||
align-content: space-evenly;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.grade-extension {
|
||||
grid-area: grade-extension;
|
||||
background-color: $pedagogy-blue;
|
||||
}
|
||||
|
||||
.grade-type {
|
||||
grid-area: grade-type;
|
||||
|
||||
> p {
|
||||
color: $pedagogy-white-text;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.grade-stars {
|
||||
grid-area: grade-stars;
|
||||
}
|
||||
}
|
||||
|
||||
.comment {
|
||||
grid-area: comment;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto auto;
|
||||
grid-template-areas:
|
||||
"anchor"
|
||||
"markdown";
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
border-left: solid;
|
||||
border-right: solid;
|
||||
border-color: $pedagogy-blue;
|
||||
}
|
||||
|
||||
.anchor {
|
||||
grid-area: anchor;
|
||||
text-align: right;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.markdown {
|
||||
grid-area: markdown;
|
||||
|
||||
min-height: 139px;
|
||||
margin-top: 0;
|
||||
margin-right: 0;
|
||||
padding: 10px;
|
||||
text-align: justify;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
grid-area: info;
|
||||
padding-bottom: 10px;
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
border-left: solid;
|
||||
border-right: solid;
|
||||
border-color: $pedagogy-blue;
|
||||
}
|
||||
|
||||
.status-reported {
|
||||
color: red;
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-end-bar {
|
||||
grid-area: comment-end-bar;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 33% auto auto;
|
||||
grid-template-rows: 2.5em;
|
||||
grid-template-areas: "author date report";
|
||||
|
||||
background-color: $pedagogy-blue;
|
||||
margin-top: -1px;
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto auto auto;
|
||||
grid-template-areas:
|
||||
"report"
|
||||
"date"
|
||||
"author";
|
||||
margin-top: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.author {
|
||||
grid-area: author;
|
||||
|
||||
padding-top: 6px;
|
||||
padding-left: 20px;
|
||||
|
||||
background-color: $pedagogy-orange;
|
||||
clip-path: polygon(0 10px, 0 100%, 350px 200%, 300px 10px);
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
clip-path: none;
|
||||
padding: 0;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $pedagogy-white-text;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: $pedagogy-hover-blue;
|
||||
}
|
||||
}
|
||||
|
||||
.date {
|
||||
grid-area: date;
|
||||
color: $pedagogy-white-text;
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
.report {
|
||||
grid-area: report;
|
||||
justify-self: right;
|
||||
padding-right: 30px;
|
||||
padding-left: 30px;
|
||||
|
||||
a {
|
||||
color: $pedagogy-white-text;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: $pedagogy-hover-blue;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
text-align: center;
|
||||
justify-self: inherit;
|
||||
padding-bottom: 7px;
|
||||
background-color: $white-color;
|
||||
|
||||
border-left: solid;
|
||||
border-right: solid;
|
||||
border-color: $pedagogy-blue;
|
||||
|
||||
a {
|
||||
color: $black-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,287 +5,287 @@ $border: .01rem solid black;
|
||||
$min_col_width: 100px;
|
||||
|
||||
.error {
|
||||
color: red !important;
|
||||
color: red !important;
|
||||
}
|
||||
|
||||
.radio-btn {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: $gap;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: $gap;
|
||||
|
||||
> input,
|
||||
> label {
|
||||
margin: 0;
|
||||
}
|
||||
> input,
|
||||
> label {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.election_vote {
|
||||
overflow-x: scroll !important;
|
||||
overflow-x: scroll !important;
|
||||
}
|
||||
|
||||
.election_table {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
|
||||
>.lists {
|
||||
>.lists {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
>tr {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
|
||||
>.column {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: $padding;
|
||||
border: $border;
|
||||
border-collapse: collapse;
|
||||
position: relative;
|
||||
min-width: $min_col_width;
|
||||
|
||||
>a{
|
||||
margin-left: $padding;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border-radius: 25%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: $gap;
|
||||
top: $gap;
|
||||
|
||||
&:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>.role {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
>tr {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: lightgrey;
|
||||
|
||||
&:hover {
|
||||
background-color: lightgrey;
|
||||
}
|
||||
|
||||
>.role_title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 0;
|
||||
padding: $padding;
|
||||
width: 100%;
|
||||
|
||||
>tr {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
|
||||
>.column {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: $padding;
|
||||
border: $border;
|
||||
border-collapse: collapse;
|
||||
position: relative;
|
||||
min-width: $min_col_width;
|
||||
|
||||
>a{
|
||||
margin-left: $padding;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border-radius: 25%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: $gap;
|
||||
top: $gap;
|
||||
|
||||
&:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
>.role_text {
|
||||
>h4 {
|
||||
margin: 0;
|
||||
}
|
||||
>p {
|
||||
margin-top: .5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>.role {
|
||||
>.role_buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: $gap;
|
||||
|
||||
> button,
|
||||
> button > i,
|
||||
> a {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #e9e9e9;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border-radius: 25%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover,
|
||||
&:hover > i {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
> button {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
> button[disabled] {
|
||||
background-color: #eee;
|
||||
cursor: not-allowed;
|
||||
|
||||
>i,
|
||||
&:hover,
|
||||
&:hover > i {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>.list_per_role {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
border: $border;
|
||||
border-collapse: collapse;
|
||||
background-color: #fff;
|
||||
padding: $padding_smaller;
|
||||
margin: 0;
|
||||
min-width: $min_col_width;
|
||||
|
||||
>tr {
|
||||
>.candidates {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
gap: $gap;
|
||||
|
||||
>.candidate {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: lightgrey;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
list-style-type: none;
|
||||
width: 100%;
|
||||
gap: $gap;
|
||||
|
||||
&:hover {
|
||||
background-color: lightgrey;
|
||||
}
|
||||
>input[type="radio"]:checked + label,
|
||||
>input[type="checkbox"]:checked + label {
|
||||
background-color: lightgray;
|
||||
border-radius: 10px;
|
||||
|
||||
>.role_title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 0;
|
||||
padding: $padding;
|
||||
width: 100%;
|
||||
|
||||
|
||||
>.role_text {
|
||||
>h4 {
|
||||
margin: 0;
|
||||
}
|
||||
>p {
|
||||
margin-top: .5em;
|
||||
}
|
||||
}
|
||||
|
||||
>.role_buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: $gap;
|
||||
|
||||
> button,
|
||||
> button > i,
|
||||
> a {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #e9e9e9;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border-radius: 25%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover,
|
||||
&:hover > i {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
> button {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
> button[disabled] {
|
||||
background-color: #eee;
|
||||
cursor: not-allowed;
|
||||
|
||||
>i,
|
||||
&:hover,
|
||||
&:hover > i {
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>.list_per_role {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
border: $border;
|
||||
border-collapse: collapse;
|
||||
>figure>.edit_btns>a:hover{
|
||||
background-color: #fff;
|
||||
padding: $padding_smaller;
|
||||
margin: 0;
|
||||
min-width: $min_col_width;
|
||||
|
||||
>.candidates {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
gap: $gap;
|
||||
|
||||
>.candidate {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
list-style-type: none;
|
||||
width: 100%;
|
||||
gap: $gap;
|
||||
|
||||
>input[type="radio"]:checked + label,
|
||||
>input[type="checkbox"]:checked + label {
|
||||
background-color: lightgray;
|
||||
border-radius: 10px;
|
||||
|
||||
>figure>.edit_btns>a:hover{
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
>label {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
>label>figure,
|
||||
>figure {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: $gap;
|
||||
padding: 10px;
|
||||
max-width: 100%;
|
||||
|
||||
>img {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
>figcaption {
|
||||
width: 100%;
|
||||
max-width: inherit !important;
|
||||
overflow: hidden;
|
||||
|
||||
h5 {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.candidate_program {
|
||||
margin: 5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
>.edit_btns {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: $gap;
|
||||
right: $gap;
|
||||
gap: $gap;
|
||||
|
||||
> a {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #e9e9e9;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border-radius: 25%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
background-color: #d8d8d8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>label {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
>label>figure,
|
||||
>figure {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: $gap;
|
||||
padding: 10px;
|
||||
max-width: 100%;
|
||||
|
||||
>img {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
>figcaption {
|
||||
width: 100%;
|
||||
max-width: inherit !important;
|
||||
overflow: hidden;
|
||||
|
||||
h5 {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.candidate_program {
|
||||
margin: 5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
>.edit_btns {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: $gap;
|
||||
right: $gap;
|
||||
gap: $gap;
|
||||
|
||||
> a {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #e9e9e9;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border-radius: 25%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
background-color: #d8d8d8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.election_details {
|
||||
margin: .5em 0;
|
||||
margin: .5em 0;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $gap;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $gap;
|
||||
}
|
||||
|
||||
.button {
|
||||
border: none;
|
||||
border: none;
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
background-color: #f2f2f2;
|
||||
padding: 0.4em;
|
||||
margin: 0.1em;
|
||||
font-size: 1.18em;
|
||||
border-radius: 5px;
|
||||
box-shadow: #dfdfdf 0px 0px 1px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
background-color: #f2f2f2;
|
||||
padding: 0.4em;
|
||||
margin: 0.1em;
|
||||
font-size: 1.18em;
|
||||
border-radius: 5px;
|
||||
box-shadow: #dfdfdf 0px 0px 1px;
|
||||
cursor: pointer;
|
||||
background: #d4d4d4;
|
||||
}
|
||||
|
||||
&_send {
|
||||
background-color: #59aee2;
|
||||
&:hover {
|
||||
color: black;
|
||||
background: #d4d4d4;
|
||||
}
|
||||
|
||||
&_send {
|
||||
background-color: #59aee2;
|
||||
&:hover {
|
||||
background-color: rgb(130, 186, 235);
|
||||
}
|
||||
background-color: rgb(130, 186, 235);
|
||||
}
|
||||
}
|
||||
}
|
@ -199,12 +199,6 @@
|
||||
> form {
|
||||
> p {
|
||||
box-sizing: border-box;
|
||||
|
||||
> input {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
> .results_on_deck > div {
|
||||
@ -219,12 +213,15 @@
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> input {
|
||||
width: 100%;
|
||||
input {
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,6 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// Django moment
|
||||
> div.mini_profile_link {
|
||||
position: relative;
|
||||
|
||||
@ -50,7 +49,7 @@
|
||||
align-items: flex-start;
|
||||
max-height: 65px;
|
||||
}
|
||||
|
||||
|
||||
> span {
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
@ -66,14 +65,14 @@
|
||||
max-height: 100%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
|
||||
|
||||
@media (max-width: 375px) {
|
||||
max-width: 100%;
|
||||
max-height: 65px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
> em {
|
||||
box-sizing: border-box;
|
||||
padding: 0 5px;
|
||||
@ -106,7 +105,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Django moment
|
||||
> a.mini_profile_link {
|
||||
display: none;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ main {
|
||||
> span {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
|
||||
> span > span,
|
||||
> span {
|
||||
display: flex;
|
||||
@ -43,7 +43,7 @@ main {
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
width: 100%;
|
||||
|
||||
|
||||
>.button {
|
||||
font-size: smaller;
|
||||
width: 100%;
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h3>{% trans %}403, Forbidden{% endtrans %}</h3>
|
||||
<h3>{% trans %}403, Forbidden{% endtrans %}</h3>
|
||||
|
||||
{{ super() }}
|
||||
{{ super() }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div id="page">
|
||||
<h3>{% trans %}404, Not Found{% endtrans %}</h3>
|
||||
</div>
|
||||
<div id="page">
|
||||
<h3>{% trans %}404, Not Found{% endtrans %}</h3>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
@ -1,27 +1,27 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<script
|
||||
src="https://browser.sentry-cdn.com/7.11.1/bundle.min.js"
|
||||
integrity="sha384-qcYSo5+/E8hEkPmHFa79GRDsGT84SRhBJHRw3+dbQyh0UwueiFP1jCsRBClEREcs"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
{{ super() }}
|
||||
<script
|
||||
src="https://browser.sentry-cdn.com/7.11.1/bundle.min.js"
|
||||
integrity="sha384-qcYSo5+/E8hEkPmHFa79GRDsGT84SRhBJHRw3+dbQyh0UwueiFP1jCsRBClEREcs"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
{% endblock head %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans %}500, Server Error{% endtrans %}</h3>
|
||||
{% if settings.SENTRY_DSN %}
|
||||
<script>
|
||||
Sentry.init({ dsn: '{{ settings.SENTRY_DSN }}' });
|
||||
Sentry.showReportDialog({
|
||||
eventId: '{{ request.sentry_last_event_id() }}',
|
||||
{% if user.is_authenticated %}
|
||||
user: {
|
||||
'name': '{{user.first_name}} {{user.last_name}}',
|
||||
'email': '{{user.email}}'
|
||||
}
|
||||
{% endif %}
|
||||
})
|
||||
</script>
|
||||
{% endif %}
|
||||
<h3>{% trans %}500, Server Error{% endtrans %}</h3>
|
||||
{% if settings.SENTRY_DSN %}
|
||||
<script>
|
||||
Sentry.init({ dsn: '{{ settings.SENTRY_DSN }}' });
|
||||
Sentry.showReportDialog({
|
||||
eventId: '{{ request.sentry_last_event_id() }}',
|
||||
{% if user.is_authenticated %}
|
||||
user: {
|
||||
'name': '{{user.first_name}} {{user.last_name}}',
|
||||
'email': '{{user.email}}'
|
||||
}
|
||||
{% endif %}
|
||||
})
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
|
@ -1,342 +1,321 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
{% block head %}
|
||||
<title>{% block title %}{% trans %}Welcome!{% endtrans %}{% endblock %} - Association des Étudiants UTBM</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="shortcut icon" href="{{ static('core/img/favicon.ico') }}">
|
||||
<link rel="stylesheet" href="{{ static('core/base.css') }}">
|
||||
<link rel="stylesheet" href="{{ static('core/jquery.datetimepicker.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ static('ajax_select/css/ajax_select.css') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/style.scss') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/markdown.scss') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/header.scss') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/navbar.scss') }}">
|
||||
<head>
|
||||
{% block head %}
|
||||
<title>{% block title %}{% trans %}Welcome!{% endtrans %}{% endblock %} - Association des Étudiants UTBM</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="shortcut icon" href="{{ static('core/img/favicon.ico') }}">
|
||||
<link rel="stylesheet" href="{{ static('core/base.css') }}">
|
||||
<link rel="stylesheet" href="{{ static('ajax_select/css/ajax_select.css') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/style.scss') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/markdown.scss') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/header.scss') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/navbar.scss') }}">
|
||||
|
||||
{% block jquery_css %}
|
||||
{% block jquery_css %}
|
||||
{# 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 %}
|
||||
<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>
|
||||
<link rel="stylesheet" href="{{ static('core/js/ui/jquery-ui.min.css') }}">
|
||||
{% endblock %}
|
||||
<link rel="preload" as="style" href="{{ static('core/font-awesome/css/font-awesome.min.css') }}" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="{{ static('core/font-awesome/css/font-awesome.min.css') }}"></noscript>
|
||||
<script defer href="{{ static('core/font-awesome/js/fontawesone.min.js') }}"></script>
|
||||
|
||||
<!-- Jquery declared here to be accessible in every django widgets -->
|
||||
<script src="{{ static('core/js/jquery-3.6.2.min.js') }}"></script>
|
||||
<script src="{{ static('core/js/jquery-3.6.2.min.js') }}"></script>
|
||||
<!-- Put here to always have acces to those functions on django widgets -->
|
||||
<script src="{{ static('core/js/script.js') }}"></script>
|
||||
<script src="{{ static('core/js/script.js') }}"></script>
|
||||
|
||||
{% block additional_css %}{% endblock %}
|
||||
{% block additional_js %}{% endblock %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
{% block additional_css %}{% endblock %}
|
||||
{% block additional_js %}{% endblock %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body>
|
||||
|
||||
<!-- The token is always passed here to be accessible from the dom -->
|
||||
<!-- See this workaround https://docs.djangoproject.com/en/2.0/ref/csrf/#acquiring-the-token-if-csrf-use-sessions-is-true -->
|
||||
{% csrf_token %}
|
||||
{% csrf_token %}
|
||||
<!-- BEGIN HEADER -->
|
||||
{% block header %}
|
||||
{% if not popup %}
|
||||
<header class="header">
|
||||
<div class="header-logo">
|
||||
<a class="header-logo-picture" href="{{ url('core:index') }}" style="background-image: url('{{ static('core/img/logo_no_text.png') }}')">
|
||||
|
||||
</a>
|
||||
<a class="header-logo-text" href="{{ url('core:index') }}">
|
||||
<span>Association des Étudiants</span>
|
||||
<span>de l'Université de Technologie de Belfort-Montbéliard</span>
|
||||
</a>
|
||||
</div>
|
||||
{% if not user.is_authenticated %}
|
||||
<div class="header-disconnected">
|
||||
<a class="button" href="{{ url('core:login') }}">{% trans %}Login{% endtrans %}</a>
|
||||
<a class="button" href="{{ url('core:register') }}">{% trans %}Register{% endtrans %}</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="header-connected">
|
||||
<div class="left">
|
||||
<form class="search" action="{{ url('core:search') }}" method="GET" id="header_search">
|
||||
<input class="header-input" type="text" placeholder="{% trans %}Search{% endtrans %}" name="query" id="search" />
|
||||
<input type="submit" value="{% trans %}Search{% endtrans %}" style="display: none;" />
|
||||
</form>
|
||||
<ul class="bars">
|
||||
{% cache 100 "counters_activity" %}
|
||||
{% for bar in Counter.objects.annotate_has_barman(user).filter(type="BAR") %}
|
||||
<li>
|
||||
{% block header %}
|
||||
{% if not popup %}
|
||||
<header class="header">
|
||||
<div class="header-logo">
|
||||
<a class="header-logo-picture" href="{{ url('core:index') }}" style="background-image: url('{{ static('core/img/logo_no_text.png') }}')">
|
||||
|
||||
</a>
|
||||
<a class="header-logo-text" href="{{ url('core:index') }}">
|
||||
<span>Association des Étudiants</span>
|
||||
<span>de l'Université de Technologie de Belfort-Montbéliard</span>
|
||||
</a>
|
||||
</div>
|
||||
{% if not user.is_authenticated %}
|
||||
<div class="header-disconnected">
|
||||
<a class="button" href="{{ url('core:login') }}">{% trans %}Login{% endtrans %}</a>
|
||||
<a class="button" href="{{ url('core:register') }}">{% trans %}Register{% endtrans %}</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="header-connected">
|
||||
<div class="left">
|
||||
<form class="search" action="{{ url('core:search') }}" method="GET" id="header_search">
|
||||
<input class="header-input" type="text" placeholder="{% trans %}Search{% endtrans %}" name="query" id="search" />
|
||||
<input type="submit" value="{% trans %}Search{% endtrans %}" style="display: none;" />
|
||||
</form>
|
||||
<ul class="bars">
|
||||
{% cache 100 "counters_activity" %}
|
||||
{% for bar in Counter.objects.annotate_has_barman(user).filter(type="BAR") %}
|
||||
<li>
|
||||
{# If the user is a barman, we redirect him directly to the barman page
|
||||
else we redirect him to the activity page #}
|
||||
{% if bar.has_annotated_barman %}
|
||||
<a href="{{ url('counter:details', counter_id=bar.id) }}">
|
||||
{% else %}
|
||||
<a href="{{ url('counter:activity', counter_id=bar.id) }}">
|
||||
{% endif %}
|
||||
{% if bar.is_inactive() %}
|
||||
<i class="fa fa-question" style="color: #f39c12"></i>
|
||||
{% elif bar.is_open %}
|
||||
<i class="fa fa-check" style="color: #2ecc71"></i>
|
||||
{% else %}
|
||||
<i class="fa fa-times" style="color: #eb2f06"></i>
|
||||
{% endif %}
|
||||
<span>{{ bar }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endcache %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="user">
|
||||
<div class="options">
|
||||
<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 %}
|
||||
style="background-image: url('{{ user.profile_pict.get_download_url() }}')"
|
||||
{% else %}
|
||||
style="background-image: url('{{ static('core/img/unknown.jpg') }}')"
|
||||
{% endif %}
|
||||
></a>
|
||||
</div>
|
||||
<div class="notification">
|
||||
<a href="#" onclick="display_notif()">
|
||||
<i class="fa fa-bell-o"></i>
|
||||
{% set notification_count = user.notifications.filter(viewed=False).count() %}
|
||||
|
||||
{% if notification_count > 0 %}
|
||||
<span>
|
||||
{% if notification_count < 100 %}
|
||||
{{ notification_count }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
<div id="header_notif">
|
||||
<ul>
|
||||
{% if user.notifications.filter(viewed=False).count() > 0 %}
|
||||
{% for n in user.notifications.filter(viewed=False).order_by('-date') %}
|
||||
<li>
|
||||
<a href="{{ url("core:notification", notif_id=n.id) }}">
|
||||
<div class="datetime">
|
||||
<span class="header_notif_date">
|
||||
{{ n.date|localtime|date(DATE_FORMAT) }}
|
||||
</span>
|
||||
<span class="header_notif_time">
|
||||
{{ n.date|localtime|time(DATETIME_FORMAT) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="reason">
|
||||
{{ n }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<li class="empty-notification">{% trans %}You do not have any unread notification{% endtrans %}</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<div class="options">
|
||||
<a href="{{ url('core:notification_list') }}">
|
||||
{% trans %}View more{% endtrans %}
|
||||
</a>
|
||||
<a href="{{ url('core:notification_list') }}?see_all">
|
||||
{% trans %}Mark all as read{% endtrans %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if bar.has_annotated_barman %}
|
||||
<a href="{{ url('counter:details', counter_id=bar.id) }}">
|
||||
{% else %}
|
||||
<a href="{{ url('counter:activity', counter_id=bar.id) }}">
|
||||
{% endif %}
|
||||
{% if bar.is_inactive() %}
|
||||
<i class="fa fa-question" style="color: #f39c12"></i>
|
||||
{% elif bar.is_open %}
|
||||
<i class="fa fa-check" style="color: #2ecc71"></i>
|
||||
{% else %}
|
||||
<i class="fa fa-times" style="color: #eb2f06"></i>
|
||||
{% endif %}
|
||||
<span>{{ bar }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endcache %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="user">
|
||||
<div class="options">
|
||||
<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 %}
|
||||
style="background-image: url('{{ user.profile_pict.get_download_url() }}')"
|
||||
{% else %}
|
||||
style="background-image: url('{{ static('core/img/unknown.jpg') }}')"
|
||||
{% endif %}
|
||||
<div class="header-lang">
|
||||
{% for language in LANGUAGES %}
|
||||
<form action="{{ url('set_language') }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input name="next" value="{{ request.path }}" type="hidden" />
|
||||
<input name="language" value="{{ language[0] }}" type="hidden" />
|
||||
<input type="submit" value="{% if language[0] == 'en' %}🇬🇧{% else %}🇫🇷{% endif %}" />
|
||||
</form>
|
||||
></a>
|
||||
</div>
|
||||
<div class="notification">
|
||||
<a href="#" onclick="display_notif()">
|
||||
<i class="fa fa-bell-o"></i>
|
||||
{% set notification_count = user.notifications.filter(viewed=False).count() %}
|
||||
|
||||
{% if notification_count > 0 %}
|
||||
<span>
|
||||
{% if notification_count < 100 %}
|
||||
{{ notification_count }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
<div id="header_notif">
|
||||
<ul>
|
||||
{% if user.notifications.filter(viewed=False).count() > 0 %}
|
||||
{% for n in user.notifications.filter(viewed=False).order_by('-date') %}
|
||||
<li>
|
||||
<a href="{{ url("core:notification", notif_id=n.id) }}">
|
||||
<div class="datetime">
|
||||
<span class="header_notif_date">
|
||||
{{ n.date|localtime|date(DATE_FORMAT) }}
|
||||
</span>
|
||||
<span class="header_notif_time">
|
||||
{{ n.date|localtime|time(DATETIME_FORMAT) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="reason">
|
||||
{{ n }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<li class="empty-notification">{% trans %}You do not have any unread notification{% endtrans %}</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<div class="options">
|
||||
<a href="{{ url('core:notification_list') }}">
|
||||
{% trans %}View more{% endtrans %}
|
||||
</a>
|
||||
<a href="{{ url('core:notification_list') }}?see_all">
|
||||
{% trans %}Mark all as read{% endtrans %}
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="header-lang">
|
||||
{% for language in LANGUAGES %}
|
||||
<form action="{{ url('set_language') }}" method="post">
|
||||
{% csrf_token %}
|
||||
<input name="next" value="{{ request.path }}" type="hidden" />
|
||||
<input name="language" value="{{ language[0] }}" type="hidden" />
|
||||
<input type="submit" value="{% if language[0] == 'en' %}🇬🇧{% else %}🇫🇷{% endif %}" />
|
||||
</form>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{% block info_boxes %}
|
||||
<div id="info_boxes">
|
||||
{% set sith = get_sith() %}
|
||||
{% if sith.alert_msg %}
|
||||
<div id="alert_box">
|
||||
{{ sith.alert_msg|markdown }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if sith.info_msg %}
|
||||
<div id="info_box">
|
||||
{{ sith.info_msg|markdown }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% else %}
|
||||
<div id="popupheader">{{ user.get_display_name() }}</div>
|
||||
{% block info_boxes %}
|
||||
<div id="info_boxes">
|
||||
{% set sith = get_sith() %}
|
||||
{% if sith.alert_msg %}
|
||||
<div id="alert_box">
|
||||
{{ sith.alert_msg|markdown }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if sith.info_msg %}
|
||||
<div id="info_box">
|
||||
{{ sith.info_msg|markdown }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% else %}
|
||||
<div id="popupheader">{{ user.get_display_name() }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
<!-- END HEADER -->
|
||||
|
||||
{% block nav %}
|
||||
{% if not popup %}
|
||||
<nav class="navbar">
|
||||
<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">
|
||||
<span class="head">{% trans %}Associations & Clubs{% endtrans %}</span>
|
||||
<ul class="content">
|
||||
<li><a href="{{ url('core:page', page_name='ae') }}">{% trans %}AE{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', page_name='clubs') }}">{% trans %}AE's clubs{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', page_name='utbm-associations') }}">{% trans %}Others UTBM's Associations{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<span class="head">{% trans %}Events{% endtrans %}</span>
|
||||
<ul class="content">
|
||||
<li><a href="{{ url('election:list') }}">{% trans %}Elections{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', page_name='ga') }}">{% trans %}Big event{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a class="link" href="{{ url('forum:main') }}">{% trans %}Forum{% endtrans %}</a>
|
||||
<a class="link" href="{{ url('sas:main') }}">{% trans %}Gallery{% endtrans %}</a>
|
||||
<a class="link" href="{{ url('eboutic:main') }}">{% trans %}Eboutic{% endtrans %}</a>
|
||||
<div class="menu">
|
||||
<span class="head">{% trans %}Services{% endtrans %}</span>
|
||||
<ul class="content">
|
||||
<li><a href="{{ url('matmat:search_clear') }}">{% trans %}Matmatronch{% endtrans %}</a></li>
|
||||
<li><a href="/launderette">{% trans %}Launderette{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:file_list') }}">{% trans %}Files{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('pedagogy:guide') }}">{% trans %}Pedagogy{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<span class="head">{% trans %}My Benefits{% endtrans %}</span>
|
||||
<ul class="content">
|
||||
<li><a href="{{ url('core:page', page_name='partenaires')}}">{% trans %}Sponsors{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', page_name='avantages') }}">{% trans %}Subscriber benefits{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<span class="head">{% trans %}Help{% endtrans %}</span>
|
||||
<ul class="content">
|
||||
<li><a href="{{ url('core:page', page_name='FAQ') }}">{% trans %}FAQ{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', 'contacts') }}">{% trans %}Contacts{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', page_name='Index') }}">{% trans %}Wiki{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
<div id="page">
|
||||
|
||||
<ul id="quick_notif">
|
||||
{% for n in quick_notifs %}
|
||||
<li>{{ n }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<div id="content">
|
||||
{% if list_of_tabs %}
|
||||
<div class="tool_bar">
|
||||
<div class="tools">
|
||||
{% for t in list_of_tabs -%}
|
||||
<a href="{{ t.url }}" {%- if current_tab==t.slug %} class="selected_tab" {%- endif -%}>{{ t.name }}</a>
|
||||
{%- endfor %}
|
||||
</div>
|
||||
{% block nav %}
|
||||
{% if not popup %}
|
||||
<nav class="navbar">
|
||||
<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">
|
||||
<span class="head">{% trans %}Associations & Clubs{% endtrans %}</span>
|
||||
<ul class="content">
|
||||
<li><a href="{{ url('core:page', page_name='ae') }}">{% trans %}AE{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', page_name='clubs') }}">{% trans %}AE's clubs{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', page_name='utbm-associations') }}">{% trans %}Others UTBM's Associations{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<span class="head">{% trans %}Events{% endtrans %}</span>
|
||||
<ul class="content">
|
||||
<li><a href="{{ url('election:list') }}">{% trans %}Elections{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', page_name='ga') }}">{% trans %}Big event{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a class="link" href="{{ url('forum:main') }}">{% trans %}Forum{% endtrans %}</a>
|
||||
<a class="link" href="{{ url('sas:main') }}">{% trans %}Gallery{% endtrans %}</a>
|
||||
<a class="link" href="{{ url('eboutic:main') }}">{% trans %}Eboutic{% endtrans %}</a>
|
||||
<div class="menu">
|
||||
<span class="head">{% trans %}Services{% endtrans %}</span>
|
||||
<ul class="content">
|
||||
<li><a href="{{ url('matmat:search_clear') }}">{% trans %}Matmatronch{% endtrans %}</a></li>
|
||||
<li><a href="/launderette">{% trans %}Launderette{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:file_list') }}">{% trans %}Files{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('pedagogy:guide') }}">{% trans %}Pedagogy{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<span class="head">{% trans %}My Benefits{% endtrans %}</span>
|
||||
<ul class="content">
|
||||
<li><a href="{{ url('core:page', page_name='partenaires')}}">{% trans %}Sponsors{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', page_name='avantages') }}">{% trans %}Subscriber benefits{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<span class="head">{% trans %}Help{% endtrans %}</span>
|
||||
<ul class="content">
|
||||
<li><a href="{{ url('core:page', page_name='FAQ') }}">{% trans %}FAQ{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', 'contacts') }}">{% trans %}Contacts{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('core:page', page_name='Index') }}">{% trans %}Wiki{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if error %}
|
||||
{{ error }}
|
||||
{% endif %}
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% if not popup %}
|
||||
<footer>
|
||||
{% block footer %}
|
||||
<div>
|
||||
<a href="{{ url('core:page', 'contacts') }}">{% trans %}Contacts{% endtrans %}</a>
|
||||
<a href="{{ url('core:page', 'legals') }}">{% trans %}Legal notices{% endtrans %}</a>
|
||||
<a href="{{ url('core:page', 'copyright_agent') }}">{% trans %}Intellectual property{% endtrans %}</a>
|
||||
<a href="{{ url('core:page', 'docs') }}">{% trans %}Help & Documentation{% endtrans %}</a>
|
||||
<a href="{{ url('core:page', 'rd') }}">{% trans %}R&D{% endtrans %}</a>
|
||||
</div>
|
||||
<a href="https://discord.gg/XK9WfPsUFm" target="_link">
|
||||
{% trans %}Site created by the IT Department of the AE{% endtrans %}
|
||||
</a>
|
||||
{% endblock %}
|
||||
<br>
|
||||
<code class="version">
|
||||
{% cache 1000 "sith_version" %}
|
||||
{% trans %}Sith version:{% endtrans %} {{ get_sith().version }}
|
||||
{% endcache %}
|
||||
</code>
|
||||
</footer>
|
||||
<div id="page">
|
||||
|
||||
<ul id="quick_notif">
|
||||
{% for n in quick_notifs %}
|
||||
<li>{{ n }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<div id="content">
|
||||
{% if list_of_tabs %}
|
||||
<div class="tool_bar">
|
||||
<div class="tools">
|
||||
{% for t in list_of_tabs -%}
|
||||
<a href="{{ t.url }}" {%- if current_tab==t.slug %} class="selected_tab" {%- endif -%}>{{ t.name }}</a>
|
||||
{%- endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<!--
|
||||
{% block tests %}
|
||||
{{ tests }}
|
||||
{% endblock %}
|
||||
-->
|
||||
{% block script %}
|
||||
<script src="{{ static('core/js/ui/jquery-ui.min.js') }}"></script>
|
||||
<script src="{{ static('core/js/ui/i18n/datepicker-fr.js') }}"></script>
|
||||
<script src="{{ static('core/js/jquery.datetimepicker.full.min.js') }}"></script>
|
||||
<script src="{{ static('ajax_select/js/ajax_select.js') }}"></script>
|
||||
<script src="{{ url('javascript-catalog') }}"></script>
|
||||
<script>
|
||||
function showMenu() {
|
||||
let navbar = document.getElementById("navbar-content");
|
||||
const current = navbar.style.getPropertyValue("display");
|
||||
navbar.style.setProperty("display", current == "none" ? "block" : "none");
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
$('.select_date').datepicker({
|
||||
changeMonth: true,
|
||||
changeYear: true,
|
||||
dayNamesShort: $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}" ].dayNamesShort,
|
||||
dayNames: $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}" ].dayNames,
|
||||
monthNamesShort: $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}" ].monthNamesShort,
|
||||
monthNames: $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}" ].monthNames,
|
||||
}).datepicker( $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}"] );
|
||||
$(document).keydown(function (e) {
|
||||
if ($(e.target).is('input')) { return }
|
||||
if ($(e.target).is('textarea')) { return }
|
||||
if ($(e.target).is('select')) { return }
|
||||
if (e.keyCode == 83) {
|
||||
$("#search").focus();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
jQuery.datetimepicker.setLocale('{{ request.LANGUAGE_CODE|lower }}');
|
||||
$('.select_datetime').datetimepicker({
|
||||
format: 'Y-m-d H:i:s',
|
||||
});
|
||||
|
||||
</script>
|
||||
{% if error %}
|
||||
{{ error }}
|
||||
{% endif %}
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if not popup %}
|
||||
<footer>
|
||||
{% block footer %}
|
||||
<div>
|
||||
<a href="{{ url('core:page', 'contacts') }}">{% trans %}Contacts{% endtrans %}</a>
|
||||
<a href="{{ url('core:page', 'legals') }}">{% trans %}Legal notices{% endtrans %}</a>
|
||||
<a href="{{ url('core:page', 'copyright_agent') }}">{% trans %}Intellectual property{% endtrans %}</a>
|
||||
<a href="{{ url('core:page', 'docs') }}">{% trans %}Help & Documentation{% endtrans %}</a>
|
||||
<a href="{{ url('core:page', 'rd') }}">{% trans %}R&D{% endtrans %}</a>
|
||||
</div>
|
||||
<a href="https://discord.gg/XK9WfPsUFm" target="_link">
|
||||
{% trans %}Site created by the IT Department of the AE{% endtrans %}
|
||||
</a>
|
||||
{% endblock %}
|
||||
<br>
|
||||
<code class="version">
|
||||
{% cache 1000 "sith_version" %}
|
||||
{% trans %}Sith version:{% endtrans %} {{ get_sith().version }}
|
||||
{% endcache %}
|
||||
</code>
|
||||
</footer>
|
||||
{% endif %}
|
||||
|
||||
{% block script %}
|
||||
<script src="{{ static('core/js/ui/jquery-ui.min.js') }}"></script>
|
||||
<script src="{{ static('ajax_select/js/ajax_select.js') }}"></script>
|
||||
<script src="{{ url('javascript-catalog') }}"></script>
|
||||
<script>
|
||||
function showMenu() {
|
||||
let navbar = document.getElementById("navbar-content");
|
||||
const current = navbar.style.getPropertyValue("display");
|
||||
navbar.style.setProperty("display", current === "none" ? "block" : "none");
|
||||
}
|
||||
|
||||
$(document).keydown(function (e) {
|
||||
if ($(e.target).is('input')) { return }
|
||||
if ($(e.target).is('textarea')) { return }
|
||||
if ($(e.target).is('select')) { return }
|
||||
if (e.keyCode === 83) {
|
||||
$("#search").focus();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,16 +1,16 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans name=form.instance.__class__._meta.verbose_name %}Create {{ name }}{% endtrans %}
|
||||
{% trans name=form.instance.__class__._meta.verbose_name %}Create {{ name }}{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% trans name=form.instance.__class__._meta.verbose_name %}Create {{ name }}{% endtrans %}</h2>
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
<h2>{% trans name=form.instance.__class__._meta.verbose_name %}Create {{ name }}{% endtrans %}</h2>
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Delete confirmation{% endtrans %}
|
||||
{% trans %}Delete confirmation{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block info_boxes %}
|
||||
@ -11,14 +11,14 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% trans %}Delete confirmation{% endtrans %}</h2>
|
||||
<form action="" method="post">{% csrf_token %}
|
||||
<h2>{% trans %}Delete confirmation{% endtrans %}</h2>
|
||||
<form action="" method="post">{% csrf_token %}
|
||||
<p>{% trans obj=object %}Are you sure you want to delete "{{ obj }}"?{% endtrans %}</p>
|
||||
<input type="submit" value="{% trans %}Confirm{% endtrans %}" />
|
||||
</form>
|
||||
<form method="GET" action="javascript:history.back();">
|
||||
</form>
|
||||
<form method="GET" action="javascript:history.back();">
|
||||
<input type="submit" name="cancel" value="{% trans %}Cancel{% endtrans %}" />
|
||||
</form>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,24 +1,24 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% if object %}
|
||||
{% trans obj=object %}Edit {{ obj }}{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}Save{% endtrans %}
|
||||
{% endif %}
|
||||
{% if object %}
|
||||
{% trans obj=object %}Edit {{ obj }}{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}Save{% endtrans %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if object %}
|
||||
<h2>{% trans obj=object %}Edit {{ obj }}{% endtrans %}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans %}Save{% endtrans %}</h2>
|
||||
{% endif %}
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
{% if object %}
|
||||
<h2>{% trans obj=object %}Edit {{ obj }}{% endtrans %}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans %}Save{% endtrans %}</h2>
|
||||
{% endif %}
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
</form>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
@ -1,62 +1,62 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{% if file %}
|
||||
{{ file.get_display_name() }}
|
||||
{% elif file_list %}
|
||||
{% trans %}File list{% endtrans %}
|
||||
{% elif new_file %}
|
||||
{% trans %}New file{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}Not found{% endtrans %}
|
||||
{% endif %}
|
||||
{% if file %}
|
||||
{{ file.get_display_name() }}
|
||||
{% elif file_list %}
|
||||
{% trans %}File list{% endtrans %}
|
||||
{% elif new_file %}
|
||||
{% trans %}New file{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}Not found{% endtrans %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% macro print_file_name(file) %}
|
||||
{% if file %}
|
||||
{{ print_file_name(file.parent) }} >
|
||||
<a href="{{ url('core:file_detail', file_id=file.id, popup=popup) }}">{{ file.get_display_name() }}</a>
|
||||
{% else %}
|
||||
<a href="{{ url('core:file_list', popup) }}">{% trans %}Files{% endtrans %}</a>
|
||||
{% endif %}
|
||||
{% if file %}
|
||||
{{ print_file_name(file.parent) }} >
|
||||
<a href="{{ url('core:file_detail', file_id=file.id, popup=popup) }}">{{ file.get_display_name() }}</a>
|
||||
{% else %}
|
||||
<a href="{{ url('core:file_list', popup) }}">{% trans %}Files{% endtrans %}</a>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
{{ print_file_name(file) }}
|
||||
{{ print_file_name(file) }}
|
||||
|
||||
<div class="tool_bar">
|
||||
<div class="tool_bar">
|
||||
<div class="tools">
|
||||
<div>
|
||||
{% set home = user.home %}
|
||||
{% if home %}
|
||||
<a href="{{ url('core:file_detail', home.id, popup) }}">{% trans %}My files{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if file %}
|
||||
<div>
|
||||
{% set home = user.home %}
|
||||
{% if home %}
|
||||
<a href="{{ url('core:file_detail', home.id, popup) }}">{% trans %}My files{% endtrans %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if file %}
|
||||
<a href="{{ url('core:file_detail', file.id, popup) }}">{% trans %}View{% endtrans %}</a>
|
||||
{% if can_edit(file, user) %}
|
||||
<a href="{{ url('core:file_edit', file_id=file.id, popup=popup) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a href="{{ url('core:file_edit', file_id=file.id, popup=popup) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
{% endif %}
|
||||
{% if can_edit_prop(file, user) %}
|
||||
<a href="{{ url('core:file_prop', file_id=file.id, popup=popup) }}">{% trans %}Prop{% endtrans %}</a>
|
||||
{% endif %}
|
||||
<a href="{{ url('core:file_prop', file_id=file.id, popup=popup) }}">{% trans %}Prop{% endtrans %}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
{% if file %}
|
||||
{% block file %}
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
{% if file %}
|
||||
{% block file %}
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
{% if popup %}
|
||||
<script>
|
||||
parent.$(".choose_file_widget").css("height", "75%");
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
{% if popup %}
|
||||
<script>
|
||||
parent.$(".choose_file_widget").css("height", "75%");
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user