Merge pull request #743 from ae-utbm/taiste

Taiste
This commit is contained in:
thomas girod 2024-07-28 21:37:38 +02:00 committed by GitHub
commit 0790ae2298
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
240 changed files with 9604 additions and 8993 deletions

View File

@ -8,11 +8,7 @@ updates:
- package-ecosystem: "pip" # See documentation for possible values - package-ecosystem: "pip" # See documentation for possible values
directory: "/" # Location of package manifests directory: "/" # Location of package manifests
schedule: schedule:
interval: "daily" interval: "weekly"
# Raise pull requests for version updates
# to pip against the `develop` branch
target-branch: "taiste" target-branch: "taiste"
reviewers:
- "ae-utbm/developpers-v3"
commit-message: commit-message:
prefix: "[UPDATE] " prefix: "[UPDATE] "

4
.gitignore vendored
View File

@ -17,4 +17,6 @@ sith/settings_custom.py
sith/search_indexes/ sith/search_indexes/
.coverage .coverage
coverage_report/ coverage_report/
doc/_build
# compiled documentation
site/

View File

@ -1,10 +1,21 @@
repos: repos:
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version. # Ruff version.
rev: v0.5.1 rev: v0.5.5
hooks: hooks:
- id: ruff # just check the code, and print the errors - id: ruff # just check the code, and print the errors
- id: ruff # actually fix the fixable errors, but print nothing - id: ruff # actually fix the fixable errors, but print nothing
args: ["--fix", "--silent"] args: ["--fix", "--silent"]
# Run the formatter. # 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"]

View File

@ -1,27 +1,27 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Accounting type list{% endtrans %} {% trans %}Accounting type list{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<p> <p>
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> > <a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
{% trans %}Accounting types{% endtrans %} {% trans %}Accounting types{% endtrans %}
</p> </p>
<hr> <hr>
<p><a href="{{ url('accounting:type_new') }}">{% trans %}New accounting type{% endtrans %}</a></p> <p><a href="{{ url('accounting:type_new') }}">{% trans %}New accounting type{% endtrans %}</a></p>
{% if accountingtype_list %} {% if accountingtype_list %}
<h3>{% trans %}Accounting type list{% endtrans %}</h3> <h3>{% trans %}Accounting type list{% endtrans %}</h3>
<ul> <ul>
{% for a in accountingtype_list %} {% for a in accountingtype_list %}
<li><a href="{{ url('accounting:type_edit', type_id=a.id) }}">{{ a }}</a></li> <li><a href="{{ url('accounting:type_edit', type_id=a.id) }}">{{ a }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% else %} {% else %}
{% trans %}There is no types in this website.{% endtrans %} {% trans %}There is no types in this website.{% endtrans %}
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,37 +1,37 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Bank account: {% endtrans %}{{ object.name }} {% trans %}Bank account: {% endtrans %}{{ object.name }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<p> <p>
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> > <a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
{{ object.name }} {{ object.name }}
</p> </p>
<hr> <hr>
<h2>{% trans %}Bank account: {% endtrans %}{{ object.name }}</h2> <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() %} {% 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> <a href="{{ url('accounting:bank_delete', b_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %} {% endif %}
<h4>{% trans %}Infos{% endtrans %}</h4> <h4>{% trans %}Infos{% endtrans %}</h4>
<ul> <ul>
<li><strong>{% trans %}IBAN: {% endtrans %}</strong>{{ object.iban }}</li> <li><strong>{% trans %}IBAN: {% endtrans %}</strong>{{ object.iban }}</li>
<li><strong>{% trans %}Number: {% endtrans %}</strong>{{ object.number }}</li> <li><strong>{% trans %}Number: {% endtrans %}</strong>{{ object.number }}</li>
</ul> </ul>
<p><a href="{{ url('accounting:club_new') }}?parent={{ object.id }}">{% trans %}New club account{% endtrans %}</a></p> <p><a href="{{ url('accounting:club_new') }}?parent={{ object.id }}">{% trans %}New club account{% endtrans %}</a></p>
<ul> <ul>
{% for c in object.club_accounts.all() %} {% for c in object.club_accounts.all() %}
<li><a href="{{ url('accounting:club_details', c_account_id=c.id) }}">{{ c }}</a> <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> - <a href="{{ url('accounting:club_edit', c_account_id=c.id) }}">{% trans %}Edit{% endtrans %}</a>
{% if c.journals.count() == 0 %} {% if c.journals.count() == 0 %}
- <a href="{{ url('accounting:club_delete', c_account_id=c.id) }}">{% trans %}Delete{% endtrans %}</a> - <a href="{{ url('accounting:club_delete', c_account_id=c.id) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %} {% endif %}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,32 +1,32 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Bank account list{% endtrans %} {% trans %}Bank account list{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<h4> <h4>
{% trans %}Accounting{% endtrans %} {% trans %}Accounting{% endtrans %}
</h4> </h4>
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %} {% 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: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:type_list') }}">{% trans %}Manage accounting types{% endtrans %}</a></p>
<p><a href="{{ url('accounting:bank_new') }}">{% trans %}New bank account{% endtrans %}</a></p> <p><a href="{{ url('accounting:bank_new') }}">{% trans %}New bank account{% endtrans %}</a></p>
{% endif %} {% endif %}
{% if bankaccount_list %} {% if bankaccount_list %}
<h3>{% trans %}Bank account list{% endtrans %}</h3> <h3>{% trans %}Bank account list{% endtrans %}</h3>
<ul> <ul>
{% for a in object_list %} {% for a in object_list %}
<li><a href="{{ url('accounting:bank_details', b_account_id=a.id) }}">{{ a }}</a> <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> - <a href="{{ url('accounting:bank_edit', b_account_id=a.id) }}">{% trans %}Edit{% endtrans %}</a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% else %} {% else %}
{% trans %}There is no accounts in this website.{% endtrans %} {% trans %}There is no accounts in this website.{% endtrans %}
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,68 +1,68 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Club account:{% endtrans %} {{ object.name }} {% trans %}Club account:{% endtrans %} {{ object.name }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<p> <p>
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> > <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:bank_details', b_account_id=object.bank_account.id) }}">{{object.bank_account }}</a> >
{{ object }} {{ object }}
</p> </p>
<hr> <hr>
<h2>{% trans %}Club account:{% endtrans %} {{ object.name }}</h2> <h2>{% trans %}Club account:{% endtrans %} {{ object.name }}</h2>
{% if user.is_root and not object.journals.exists() %} {% if user.is_root and not object.journals.exists() %}
<a href="{{ url('accounting:club_delete', c_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('accounting:club_delete', c_account_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %} {% endif %}
{% if user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %} {% 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> <p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
{% endif %} {% endif %}
<p><a href="{{ url('accounting:label_list', clubaccount_id=object.id) }}">{% trans %}Label list{% endtrans %}</a></p> <p><a href="{{ url('accounting:label_list', clubaccount_id=object.id) }}">{% trans %}Label list{% endtrans %}</a></p>
{% if not object.has_open_journal() %} {% if not object.has_open_journal() %}
<p><a href="{{ url('accounting:journal_new') }}?parent={{ object.id }}">{% trans %}New journal{% endtrans %}</a></p> <p><a href="{{ url('accounting:journal_new') }}?parent={{ object.id }}">{% trans %}New journal{% endtrans %}</a></p>
{% else %} {% else %}
<p>{% trans %}You can not create new journal while you still have one opened{% endtrans %}</p> <p>{% trans %}You can not create new journal while you still have one opened{% endtrans %}</p>
{% endif %} {% endif %}
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Name{% endtrans %}</td> <td>{% trans %}Name{% endtrans %}</td>
<td>{% trans %}Start{% endtrans %}</td> <td>{% trans %}Start{% endtrans %}</td>
<td>{% trans %}End{% endtrans %}</td> <td>{% trans %}End{% endtrans %}</td>
<td>{% trans %}Amount{% endtrans %}</td> <td>{% trans %}Amount{% endtrans %}</td>
<td>{% trans %}Effective amount{% endtrans %}</td> <td>{% trans %}Effective amount{% endtrans %}</td>
<td>{% trans %}Closed{% endtrans %}</td> <td>{% trans %}Closed{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for j in object.journals.all() %} {% for j in object.journals.all() %}
<tr> <tr>
<td>{{ j.name }}</td> <td>{{ j.name }}</td>
<td>{{ j.start_date }}</td> <td>{{ j.start_date }}</td>
{% if j.end_date %} {% if j.end_date %}
<td>{{ j.end_date }}</td> <td>{{ j.end_date }}</td>
{% else %} {% else %}
<td> - </td> <td> - </td>
{% endif %} {% endif %}
<td>{{ j.amount }} €</td> <td>{{ j.amount }} €</td>
<td>{{ j.effective_amount }} €</td> <td>{{ j.effective_amount }} €</td>
{% if j.closed %} {% if j.closed %}
<td>{% trans %}Yes{% endtrans %}</td> <td>{% trans %}Yes{% endtrans %}</td>
{% else %} {% else %}
<td>{% trans %}No{% endtrans %}</td> <td>{% trans %}No{% endtrans %}</td>
{% endif %} {% endif %}
<td> <a href="{{ url('accounting:journal_details', j_id=j.id) }}">{% trans %}View{% endtrans %}</a> <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> <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 %} {% 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> <a href="{{ url('accounting:journal_delete', j_id=j.id) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,30 +1,30 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Company list{% endtrans %} {% trans %}Company list{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
{% if user.is_root {% if user.is_root
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) 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> <p><a href="{{ url('accounting:co_new') }}">{% trans %}Create new company{% endtrans %}</a></p>
{% endif %} {% endif %}
<br/> <br/>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Companies{% endtrans %}</td> <td>{% trans %}Companies{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for o in object_list %} {% for o in object_list %}
<tr> <tr>
<td><a href="{{ url('accounting:co_edit', co_id=o.id) }}">{{ o.get_display_name() }}</a></td> <td><a href="{{ url('accounting:co_edit', co_id=o.id) }}">{{ o.get_display_name() }}</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,103 +1,103 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}General journal:{% endtrans %} {{ object.name }} {% trans %}General journal:{% endtrans %} {{ object.name }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<p> <p>
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> > <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: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:club_details', c_account_id=object.club_account.id) }}">{{ object.club_account }}</a> >
{{ object.name }} {{ object.name }}
</p> </p>
<hr> <hr>
<h2>{% trans %}General journal:{% endtrans %} {{ object.name }}</h2> <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_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: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><a href="{{ url('accounting:co_list') }}">{% trans %}Company list{% endtrans %}</a></p>
<p><strong>{% trans %}Amount: {% endtrans %}</strong>{{ object.amount }} € - <p><strong>{% trans %}Amount: {% endtrans %}</strong>{{ object.amount }} € -
<strong>{% trans %}Effective amount: {% endtrans %}</strong>{{ object.effective_amount }} €</p> <strong>{% trans %}Effective amount: {% endtrans %}</strong>{{ object.effective_amount }} €</p>
{% if object.closed %} {% if object.closed %}
<p>{% trans %}Journal is closed, you can not create operation{% endtrans %}</p> <p>{% trans %}Journal is closed, you can not create operation{% endtrans %}</p>
{% else %} {% else %}
<p><a href="{{ url('accounting:op_new', j_id=object.id) }}">{% trans %}New operation{% endtrans %}</a></p> <p><a href="{{ url('accounting:op_new', j_id=object.id) }}">{% trans %}New operation{% endtrans %}</a></p>
</br> </br>
{% endif %} {% endif %}
<div class="journal-table"> <div class="journal-table">
<table> <table>
<thead> <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> <tr>
<td>{% trans %}Nb{% endtrans %}</td> <td>{{ o.number }}</td>
<td>{% trans %}Date{% endtrans %}</td> <td>{{ o.date }}</td>
<td>{% trans %}Label{% endtrans %}</td> <td>{{ o.label or "" }}</td>
<td>{% trans %}Amount{% endtrans %}</td> {% if o.accounting_type.movement_type == "DEBIT" %}
<td>{% trans %}Payment mode{% endtrans %}</td> <td class="neg-amount">&nbsp;{{ o.amount }}&nbsp;€</td>
<td>{% trans %}Target{% endtrans %}</td> {% else %}
<td>{% trans %}Code{% endtrans %}</td> <td class="pos-amount">&nbsp;{{ o.amount }}&nbsp;€</td>
<td>{% trans %}Nature{% endtrans %}</td> {% endif %}
<td>{% trans %}Done{% endtrans %}</td> <td>{{ o.get_mode_display() }}</td>
<td>{% trans %}Comment{% endtrans %}</td> {% if o.target_type == "OTHER" %}
<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">&nbsp;{{ o.amount }}&nbsp;€</td>
{% else %}
<td class="pos-amount">&nbsp;{{ o.amount }}&nbsp;€</td>
{% endif %}
<td>{{ o.get_mode_display() }}</td>
{% if o.target_type == "OTHER" %}
<td>{{ o.target_label }}</td> <td>{{ o.target_label }}</td>
{% else %} {% else %}
<td><a href="{{ o.target.get_absolute_url() }}">{{ o.target.get_display_name() }}</a></td> <td><a href="{{ o.target.get_absolute_url() }}">{{ o.target.get_display_name() }}</a></td>
{% endif %} {% endif %}
<td>{{ o.accounting_type.code }}</td> <td>{{ o.accounting_type.code }}</td>
<td>{{ o.accounting_type.label }}</td> <td>{{ o.accounting_type.label }}</td>
{% if o.done %} {% if o.done %}
<td>{% trans %}Yes{% endtrans %}</td> <td>{% trans %}Yes{% endtrans %}</td>
{% else %} {% else %}
<td>{% trans %}No{% endtrans %}</td> <td>{% trans %}No{% endtrans %}</td>
{% endif %} {% endif %}
<td>{{ o.remark }} <td>{{ o.remark }}
{% if not o.linked_operation and o.target_type == "ACCOUNT" and not o.target.has_open_journal() %} {% if not o.linked_operation and o.target_type == "ACCOUNT" and not o.target.has_open_journal() %}
<p><strong> <p><strong>
{% trans %}Warning: this operation has no linked operation because the targeted club account has no opened journal.{% endtrans %} {% trans %}Warning: this operation has no linked operation because the targeted club account has no opened journal.{% endtrans %}
</strong></p> </strong></p>
<p><strong> <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 %} {% 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> </strong></p>
{% endif %} {% endif %}
</td> </td>
{% if o.invoice %} {% if o.invoice %}
<td><a href="{{ url('core:download', file_id=o.invoice.id) }}">{{ o.invoice.name }}</a></td> <td><a href="{{ url('core:download', file_id=o.invoice.id) }}">{{ o.invoice.name }}</a></td>
{% else %} {% else %}
<td>-</td> <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 %} {% endif %}
<td> {% endif %}
{% </td>
if o.journal.club_account.bank_account.name not in ["AE TI", "TI"] <td><a href="{{ url('accounting:op_pdf', op_id=o.id) }}">{% trans %}Generate{% endtrans %}</a></td>
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) </tr>
%} {% endfor %}
{% if not o.journal.closed %} </tbody>
<a href="{{ url('accounting:op_edit', op_id=o.id) }}">{% trans %}Edit{% endtrans %}</a> </table>
{% endif %} </div>
{% endif %} </div>
</td>
<td><a href="{{ url('accounting:op_pdf', op_id=o.id) }}">{% trans %}Generate{% endtrans %}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,33 +1,33 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}General journal:{% endtrans %} {{ object.name }} {% trans %}General journal:{% endtrans %} {{ object.name }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<h3>{% trans %}Accounting statement: {% endtrans %} {{ object.name }}</h3> <h3>{% trans %}Accounting statement: {% endtrans %} {{ object.name }}</h3>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Operation type{% endtrans %}</td> <td>{% trans %}Operation type{% endtrans %}</td>
<td>{% trans %}Sum{% endtrans %}</td> <td>{% trans %}Sum{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for k,v in statement.items() %} {% for k,v in statement.items() %}
<tr> <tr>
<td>{{ k }}</td> <td>{{ k }}</td>
<td>{{ "%.2f" % v }}</td> <td>{{ "%.2f" % v }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<p><strong>{% trans %}Amount: {% endtrans %}</strong>{{ "%.2f" % object.amount }} €</p> <p><strong>{% trans %}Amount: {% endtrans %}</strong>{{ "%.2f" % object.amount }} €</p>
<p><strong>{% trans %}Effective amount: {% endtrans %}</strong>{{ "%.2f" %object.effective_amount }} €</p> <p><strong>{% trans %}Effective amount: {% endtrans %}</strong>{{ "%.2f" %object.effective_amount }} €</p>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,57 +1,57 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}General journal:{% endtrans %} {{ object.name }} {% trans %}General journal:{% endtrans %} {{ object.name }}
{% endblock %} {% endblock %}
{% macro display_tables(dict) %} {% macro display_tables(dict) %}
<div id="accounting"> <div id="accounting">
<h6>{% trans %}Credit{% endtrans %}</h6> <h6>{% trans %}Credit{% endtrans %}</h6>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Nature of operation{% endtrans %}</td> <td>{% trans %}Nature of operation{% endtrans %}</td>
<td>{% trans %}Sum{% endtrans %}</td> <td>{% trans %}Sum{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for k,v in dict['CREDIT'].items() %} {% for k,v in dict['CREDIT'].items() %}
<tr> <tr>
<td>{{ k }}</td> <td>{{ k }}</td>
<td>{{ "%.2f" % v }}</td> <td>{{ "%.2f" % v }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% trans %}Total: {% endtrans %}{{ "%.2f" % dict['CREDIT_sum'] }} {% trans %}Total: {% endtrans %}{{ "%.2f" % dict['CREDIT_sum'] }}
<h6>{% trans %}Debit{% endtrans %}</h6> <h6>{% trans %}Debit{% endtrans %}</h6>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Nature of operation{% endtrans %}</td> <td>{% trans %}Nature of operation{% endtrans %}</td>
<td>{% trans %}Sum{% endtrans %}</td> <td>{% trans %}Sum{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for k,v in dict['DEBIT'].items() %} {% for k,v in dict['DEBIT'].items() %}
<tr> <tr>
<td>{{ k }}</td> <td>{{ k }}</td>
<td>{{ "%.2f" % v }}</td> <td>{{ "%.2f" % v }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% trans %}Total: {% endtrans %}{{ "%.2f" % dict['DEBIT_sum'] }} {% trans %}Total: {% endtrans %}{{ "%.2f" % dict['DEBIT_sum'] }}
{% endmacro %} {% endmacro %}
{% block content %} {% block content %}
<h3>{% trans %}Statement by nature: {% endtrans %} {{ object.name }}</h3> <h3>{% trans %}Statement by nature: {% endtrans %} {{ object.name }}</h3>
{% for k,v in statement.items() %} {% for k,v in statement.items() %}
<h4 style="background: lightblue; padding: 4px;">{{ k }} : {{ "%.2f" % (v['CREDIT_sum'] - v['DEBIT_sum']) }}</h4> <h4 style="background: lightblue; padding: 4px;">{{ k }} : {{ "%.2f" % (v['CREDIT_sum'] - v['DEBIT_sum']) }}</h4>
{{ display_tables(v) }} {{ display_tables(v) }}
<hr> <hr>
{% endfor %} {% endfor %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,37 +1,37 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}General journal:{% endtrans %} {{ object.name }} {% trans %}General journal:{% endtrans %} {{ object.name }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<h3>{% trans %}Statement by person: {% endtrans %} {{ object.name }}</h3> <h3>{% trans %}Statement by person: {% endtrans %} {{ object.name }}</h3>
<h4>{% trans %}Credit{% endtrans %}</h4> <h4>{% trans %}Credit{% endtrans %}</h4>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Target of the operation{% endtrans %}</td> <td>{% trans %}Target of the operation{% endtrans %}</td>
<td>{% trans %}Sum{% endtrans %}</td> <td>{% trans %}Sum{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for key in credit_statement.keys() %} {% for key in credit_statement.keys() %}
<tr> <tr>
{% if key.target_type == "OTHER" %} {% if key.target_type == "OTHER" %}
<td>{{ o.target_label }}</td> <td>{{ o.target_label }}</td>
{% elif key %} {% elif key %}
<td><a href="{{ key.get_absolute_url() }}">{{ key.get_display_name() }}</a></td> <td><a href="{{ key.get_absolute_url() }}">{{ key.get_display_name() }}</a></td>
{% else %} {% else %}
<td></td> <td></td>
{% endif %} {% endif %}
<td>{{ "%.2f" % credit_statement[key] }}</td> <td>{{ "%.2f" % credit_statement[key] }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
@ -40,29 +40,29 @@
<h4>{% trans %}Debit{% endtrans %}</h4> <h4>{% trans %}Debit{% endtrans %}</h4>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Target of the operation{% endtrans %}</td> <td>{% trans %}Target of the operation{% endtrans %}</td>
<td>{% trans %}Sum{% endtrans %}</td> <td>{% trans %}Sum{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for key in debit_statement.keys() %} {% for key in debit_statement.keys() %}
<tr> <tr>
{% if key.target_type == "OTHER" %} {% if key.target_type == "OTHER" %}
<td>{{ o.target_label }}</td> <td>{{ o.target_label }}</td>
{% elif key %} {% elif key %}
<td><a href="{{ key.get_absolute_url() }}">{{ key.get_display_name() }}</a></td> <td><a href="{{ key.get_absolute_url() }}">{{ key.get_display_name() }}</a></td>
{% else %} {% else %}
<td></td> <td></td>
{% endif %} {% endif %}
<td>{{ "%.2f" % debit_statement[key] }}</td> <td>{{ "%.2f" % debit_statement[key] }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<p>Total : {{ "%.2f" % total_debit }}</p> <p>Total : {{ "%.2f" % total_debit }}</p>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,36 +1,36 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Label list{% endtrans %} {% trans %}Label list{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<p> <p>
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> > <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: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> <a href="{{ url('accounting:club_details', c_account_id=object.id) }}">{{ object }}</a>
</p> </p>
<hr> <hr>
<p><a href="{{ url('accounting:club_details', c_account_id=object.id) }}">{% trans %}Back to club account{% endtrans %}</a></p> <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) %} {% 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> <p><a href="{{ url('accounting:label_new') }}?parent={{ object.id }}">{% trans %}New label{% endtrans %}</a></p>
{% endif %} {% endif %}
{% if object.labels.all() %} {% if object.labels.all() %}
<h3>{% trans %}Label list{% endtrans %}</h3> <h3>{% trans %}Label list{% endtrans %}</h3>
<ul> <ul>
{% for l in object.labels.all() %} {% for l in object.labels.all() %}
<li><a href="{{ url('accounting:label_edit', label_id=l.id) }}">{{ l }}</a> <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) %} {% 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 %} {% endif %}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% else %} {% else %}
{% trans %}There is no label in this club account.{% endtrans %} {% trans %}There is no label in this club account.{% endtrans %}
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,123 +1,123 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Edit operation{% endtrans %} {% trans %}Edit operation{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<p> <p>
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> > <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: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: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> > <a href="{{ url('accounting:journal_details', j_id=object.id) }}">{{ object.name }}</a> >
{% trans %}Edit operation{% endtrans %} {% trans %}Edit operation{% endtrans %}
</p> </p>
<hr> <hr>
<h2>{% trans %}Edit operation{% endtrans %}</h2> <h2>{% trans %}Edit operation{% endtrans %}</h2>
<form action="" method="post"> <form action="" method="post">
{% csrf_token %} {% csrf_token %}
{{ form.non_field_errors() }} {{ form.non_field_errors() }}
{{ form.journal }} {{ form.journal }}
{{ form.target_id }} {{ form.target_id }}
<p>{{ form.amount.errors }}<label for="{{ form.amount.name }}">{{ form.amount.label }}</label> {{ form.amount }}</p> <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> <p>{{ form.remark.errors }}<label for="{{ form.remark.name }}">{{ form.remark.label }}</label> {{ form.remark }}</p>
<br /> <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> <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> <p>{{ form.target_type.errors }}<label for="{{ form.target_type.name }}">{{ form.target_type.label }}</label> {{ form.target_type }}</p>
{{ form.user }} {{ form.user }}
{{ form.club }} {{ form.club }}
{{ form.club_account }} {{ form.club_account }}
{{ form.company }} {{ form.company }}
{{ form.target_label }} {{ form.target_label }}
<span id="id_need_link_full"><label>{{ form.need_link.label }}</label> {{ form.need_link }}</span> <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.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.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> {{ <p>{{ form.cheque_number.errors }}<label for="{{ form.cheque_number.name }}">{{ form.cheque_number.label }}</label> {{
form.cheque_number }}</p> form.cheque_number }}</p>
<p>{{ form.invoice.errors }}<label for="{{ form.invoice.name }}">{{ form.invoice.label }}</label> {{ form.invoice }}</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 }}">{{ <p>{{ form.simpleaccounting_type.errors }}<label for="{{ form.simpleaccounting_type.name }}">{{
form.simpleaccounting_type.label }}</label> {{ form.simpleaccounting_type }}</p> 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.accounting_type.errors }}<label for="{{ form.accounting_type.name }}">{{ form.accounting_type.label }}</label> {{
form.accounting_type }}</p> form.accounting_type }}</p>
<p>{{ form.label.errors }}<label for="{{ form.label.name }}">{{ form.label.label }}</label> {{ form.label }}</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> <p>{{ form.done.errors }}<label for="{{ form.done.name }}">{{ form.done.label }}</label> {{ form.done }}</p>
{% if form.instance.linked_operation %} {% if form.instance.linked_operation %}
{% set obj = form.instance.linked_operation %} {% set obj = form.instance.linked_operation %}
<p><strong>{% trans %}Linked operation:{% endtrans %}</strong><br> <p><strong>{% trans %}Linked operation:{% endtrans %}</strong><br>
<a href="{{ url('accounting:bank_details', b_account_id=obj.journal.club_account.bank_account.id) }}"> <a href="{{ url('accounting:bank_details', b_account_id=obj.journal.club_account.bank_account.id) }}">
{{obj.journal.club_account.bank_account }}</a> > {{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: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> > <a href="{{ url('accounting:journal_details', j_id=obj.journal.id) }}">{{ obj.journal }}</a> >
{{ obj.number }} {{ obj.number }}
</p> </p>
{% endif %} {% endif %}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form> </form>
{% endblock %} {% endblock %}
{% block script %} {% block script %}
{{ super() }} {{ super() }}
<script> <script>
$( function() { $( function() {
var target_type = $('#id_target_type'); var target_type = $('#id_target_type');
var user = $('#id_user_wrapper'); var user = $('#id_user_wrapper');
var club = $('#id_club_wrapper'); var club = $('#id_club_wrapper');
var club_account = $('#id_club_account_wrapper'); var club_account = $('#id_club_account_wrapper');
var company = $('#id_company_wrapper'); var company = $('#id_company_wrapper');
var other = $('#id_target_label'); var other = $('#id_target_label');
var need_link = $('#id_need_link_full'); var need_link = $('#id_need_link_full');
function update_targets () { function update_targets () {
if (target_type.val() == "USER") { if (target_type.val() == "USER") {
console.log(user); console.log(user);
user.show(); user.show();
club.hide(); club.hide();
club_account.hide(); club_account.hide();
company.hide(); company.hide();
other.hide(); other.hide();
need_link.hide(); need_link.hide();
} else if (target_type.val() == "ACCOUNT") { } else if (target_type.val() == "ACCOUNT") {
club_account.show(); club_account.show();
need_link.show(); need_link.show();
user.hide(); user.hide();
club.hide(); club.hide();
company.hide(); company.hide();
other.hide(); other.hide();
} else if (target_type.val() == "CLUB") { } else if (target_type.val() == "CLUB") {
club.show(); club.show();
user.hide(); user.hide();
club_account.hide(); club_account.hide();
company.hide(); company.hide();
other.hide(); other.hide();
need_link.hide(); need_link.hide();
} else if (target_type.val() == "COMPANY") { } else if (target_type.val() == "COMPANY") {
company.show(); company.show();
user.hide(); user.hide();
club_account.hide(); club_account.hide();
club.hide(); club.hide();
other.hide(); other.hide();
need_link.hide(); need_link.hide();
} else if (target_type.val() == "OTHER") { } else if (target_type.val() == "OTHER") {
other.show(); other.show();
user.hide(); user.hide();
club.hide(); club.hide();
club_account.hide(); club_account.hide();
company.hide(); company.hide();
need_link.hide(); need_link.hide();
} else { } else {
company.hide(); company.hide();
user.hide(); user.hide();
club_account.hide(); club_account.hide();
club.hide(); club.hide();
other.hide(); other.hide();
need_link.hide(); need_link.hide();
} }
} }
update_targets(); update_targets();
target_type.change(update_targets); target_type.change(update_targets);
} ); } );
</script> </script>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,16 +1,16 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Refound account{% endtrans %} {% trans %}Refound account{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<h3>{% trans %}Refound account{% endtrans %}</h3> <h3>{% trans %}Refound account{% endtrans %}</h3>
<form action="" method="post"> <form action="" method="post">
{% csrf_token %} {% csrf_token %}
{{ form.as_p() }} {{ form.as_p() }}
<p><input type="submit" value="{% trans %}Refound{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Refound{% endtrans %}" /></p>
</form> </form>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,27 +1,27 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Simplified type list{% endtrans %} {% trans %}Simplified type list{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="accounting"> <div id="accounting">
<p> <p>
<a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> > <a href="{{ url('accounting:bank_list') }}">{% trans %}Accounting{% endtrans %}</a> >
{% trans %}Simplified types{% endtrans %} {% trans %}Simplified types{% endtrans %}
</p> </p>
<hr> <hr>
<p><a href="{{ url('accounting:simple_type_new') }}">{% trans %}New simplified type{% endtrans %}</a></p> <p><a href="{{ url('accounting:simple_type_new') }}">{% trans %}New simplified type{% endtrans %}</a></p>
{% if simplifiedaccountingtype_list %} {% if simplifiedaccountingtype_list %}
<h3>{% trans %}Simplified type list{% endtrans %}</h3> <h3>{% trans %}Simplified type list{% endtrans %}</h3>
<ul> <ul>
{% for a in simplifiedaccountingtype_list %} {% for a in simplifiedaccountingtype_list %}
<li><a href="{{ url('accounting:simple_type_edit', type_id=a.id) }}">{{ a }}</a></li> <li><a href="{{ url('accounting:simple_type_edit', type_id=a.id) }}">{{ a }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% else %} {% else %}
{% trans %}There is no types in this website.{% endtrans %} {% trans %}There is no types in this website.{% endtrans %}
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -264,33 +264,26 @@ class TestOperation(TestCase):
) )
self.assertContains(response, "Total : 5575.72", status_code=200) self.assertContains(response, "Total : 5575.72", status_code=200)
self.assertContains(response, "Total : 71.42") self.assertContains(response, "Total : 71.42")
self.assertContains( content = response.content.decode()
response, self.assertInHTML(
""" """<td><a href="/user/1/">S&#39; Kia</a></td><td>3.00</td>""", content
<td><a href="/user/1/">S&#39; Kia</a></td>
<td>3.00</td>""",
) )
self.assertContains( self.assertInHTML(
response, """<td><a href="/user/1/">S&#39; Kia</a></td><td>823.00</td>""", content
"""
<td><a href="/user/1/">S&#39; Kia</a></td>
<td>823.00</td>""",
) )
def test_accounting_statement(self): def test_accounting_statement(self):
response = self.client.get( response = self.client.get(
reverse("accounting:journal_accounting_statement", args=[self.journal.id]) reverse("accounting:journal_accounting_statement", args=[self.journal.id])
) )
self.assertContains( assert response.status_code == 200
response, self.assertInHTML(
""" """
<tr> <tr>
<td>443 - Crédit - Ce code n&#39;existe pas</td> <td>443 - Crédit - Ce code n&#39;existe pas</td>
<td>3.00</td> <td>3.00</td>
</tr>""", </tr>""",
status_code=200, response.content.decode(),
) )
self.assertContains( self.assertContains(
response, response,

View File

@ -29,7 +29,7 @@ from django.utils.translation import gettext_lazy as _
from club.models import Club, Mailing, MailingSubscription, Membership from club.models import Club, Mailing, MailingSubscription, Membership
from core.models import User from core.models import User
from core.views.forms import SelectDate, TzAwareDateTimeField from core.views.forms import SelectDate, SelectDateTime
from counter.models import Counter from counter.models import Counter
@ -149,8 +149,12 @@ class MailingForm(forms.Form):
class SellingsForm(forms.Form): class SellingsForm(forms.Form):
begin_date = TzAwareDateTimeField(label=_("Begin date"), required=False) begin_date = forms.DateTimeField(
end_date = TzAwareDateTimeField(label=_("End date"), required=False) label=_("Begin date"), widget=SelectDateTime, required=False
)
end_date = forms.DateTimeField(
label=_("End date"), widget=SelectDateTime, required=False
)
counters = forms.ModelMultipleChoiceField( counters = forms.ModelMultipleChoiceField(
Counter.objects.order_by("name").all(), label=_("Counter"), required=False Counter.objects.order_by("name").all(), label=_("Counter"), required=False

View File

@ -2,16 +2,16 @@
{% from 'core/macros.jinja' import user_profile_link %} {% from 'core/macros.jinja' import user_profile_link %}
{% block content %} {% block content %}
<div id="club_detail"> <div id="club_detail">
{% if club.logo %} {% if club.logo %}
<div class="club_logo"><img src="{{ club.logo.url }}" alt="{{ club.unix_name }}"></div> <div class="club_logo"><img src="{{ club.logo.url }}" alt="{{ club.unix_name }}"></div>
{% endif %} {% endif %}
{% if page_revision %} {% if page_revision %}
{{ page_revision|markdown }} {{ page_revision|markdown }}
{% else %} {% else %}
<h3>{% trans %}Club{% endtrans %}</h3> <h3>{% trans %}Club{% endtrans %}</h3>
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,48 +1,48 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Club list{% endtrans %} {% trans %}Club list{% endtrans %}
{% endblock %} {% endblock %}
{% macro display_club(club) -%} {% macro display_club(club) -%}
{% if club.is_active or user.is_root %} {% 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.president %} - <a href="{{ url('core:user_profile', user_id=club.president.user.id) }}">{{ club.president.user }}</a>{% endif %} <li><a href="{{ url('club:club_view', club_id=club.id) }}">{{ club.name }}</a>
{% if club.short_description %}<p>{{ club.short_description|markdown }}</p>{% endif %}
{% endif %}
{%- if club.children.all()|length != 0 %} {% if not club.is_active %}
<ul> ({% trans %}inactive{% endtrans %})
{%- for c in club.children.order_by('name') %} {% endif %}
{{ display_club(c) }}
{%- endfor %} {% if club.president %} - <a href="{{ url('core:user_profile', user_id=club.president.user.id) }}">{{ club.president.user }}</a>{% endif %}
</ul> {% if club.short_description %}<p>{{ club.short_description|markdown }}</p>{% endif %}
{%- endif -%}
</li> {% endif %}
{%- if club.children.all()|length != 0 %}
<ul>
{%- for c in club.children.order_by('name') %}
{{ display_club(c) }}
{%- endfor %}
</ul>
{%- endif -%}
</li>
{%- endmacro %} {%- endmacro %}
{% block content %} {% block content %}
{% if user.is_root %} {% if user.is_root %}
<p><a href="{{ url('club:club_new') }}">{% trans %}New club{% endtrans %}</a></p> <p><a href="{{ url('club:club_new') }}">{% trans %}New club{% endtrans %}</a></p>
{% endif %} {% endif %}
{% if club_list %} {% if club_list %}
<h3>{% trans %}Club list{% endtrans %}</h3> <h3>{% trans %}Club list{% endtrans %}</h3>
<ul> <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) }} {{ display_club(c) }}
{%- endfor %} {%- endfor %}
</ul> </ul>
{% else %} {% else %}
{% trans %}There is no club in this website.{% endtrans %} {% trans %}There is no club in this website.{% endtrans %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -2,81 +2,81 @@
{% from 'core/macros.jinja' import user_profile_link, select_all_checkbox %} {% from 'core/macros.jinja' import user_profile_link, select_all_checkbox %}
{% block content %} {% block content %}
<h2>{% trans %}Club members{% endtrans %}</h2> <h2>{% trans %}Club members{% endtrans %}</h2>
{% if members %} {% if members %}
<form action="{{ url('club:club_members', club_id=club.id) }}" id="users_old" method="post"> <form action="{{ url('club:club_members', club_id=club.id) }}" id="users_old" method="post">
{% csrf_token %} {% csrf_token %}
{% set users_old = dict(form.users_old | groupby("choice_label")) %} {% set users_old = dict(form.users_old | groupby("choice_label")) %}
{% if users_old %} {% if users_old %}
{{ select_all_checkbox("users_old") }} {{ select_all_checkbox("users_old") }}
<p></p> <p></p>
{% endif %} {% endif %}
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}User{% endtrans %}</td> <td>{% trans %}User{% endtrans %}</td>
<td>{% trans %}Role{% endtrans %}</td> <td>{% trans %}Role{% endtrans %}</td>
<td>{% trans %}Description{% endtrans %}</td> <td>{% trans %}Description{% endtrans %}</td>
<td>{% trans %}Since{% endtrans %}</td> <td>{% trans %}Since{% endtrans %}</td>
{% if users_old %} {% if users_old %}
<td>{% trans %}Mark as old{% endtrans %}</td> <td>{% trans %}Mark as old{% endtrans %}</td>
{% endif %} {% endif %}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for m in members %} {% for m in members %}
<tr> <tr>
<td>{{ user_profile_link(m.user) }}</td> <td>{{ user_profile_link(m.user) }}</td>
<td>{{ settings.SITH_CLUB_ROLES[m.role] }}</td> <td>{{ settings.SITH_CLUB_ROLES[m.role] }}</td>
<td>{{ m.description }}</td> <td>{{ m.description }}</td>
<td>{{ m.start_date }}</td> <td>{{ m.start_date }}</td>
{% if users_old %} {% if users_old %}
<td> <td>
{% set user_old = users_old[m.user.get_display_name()] %} {% set user_old = users_old[m.user.get_display_name()] %}
{% if user_old %} {% if user_old %}
{{ user_old[0].tag() }} {{ user_old[0].tag() }}
{% endif %} {% endif %}
</td> </td>
{% endif %} {% endif %}
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{{ form.users_old.errors }} {{ form.users_old.errors }}
{% if users_old %} {% if users_old %}
<p></p> <p></p>
<input type="submit" name="submit" value="{% trans %}Mark as old{% endtrans %}"> <input type="submit" name="submit" value="{% trans %}Mark as old{% endtrans %}">
{% endif %} {% endif %}
</form> </form>
{% else %} {% else %}
<p>{% trans %}There are no members in this club.{% endtrans %}</p> <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 %} {% endif %}
<form action="{{ url('club:club_members', club_id=club.id) }}" id="add_users" method="post"> <p>
{% csrf_token %} {{ form.description.errors }}
{{ form.non_field_errors() }} <label for="{{ form.description.id_for_label }}">{{ form.description.label }} :</label>
<p> {{ form.description }}
{{ form.users.errors }} </p>
<label for="{{ form.users.id_for_label }}">{{ form.users.label }} :</label> <p><input type="submit" value="{% trans %}Add{% endtrans %}" /></p>
{{ form.users }} </form>
<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>
{% endblock %} {% endblock %}

View File

@ -2,27 +2,27 @@
{% from 'core/macros.jinja' import user_profile_link %} {% from 'core/macros.jinja' import user_profile_link %}
{% block content %} {% block content %}
<h2>{% trans %}Club old members{% endtrans %}</h2> <h2>{% trans %}Club old members{% endtrans %}</h2>
<table> <table>
<thead> <thead>
<td>{% trans %}User{% endtrans %}</td> <td>{% trans %}User{% endtrans %}</td>
<td>{% trans %}Role{% endtrans %}</td> <td>{% trans %}Role{% endtrans %}</td>
<td>{% trans %}Description{% endtrans %}</td> <td>{% trans %}Description{% endtrans %}</td>
<td>{% trans %}From{% endtrans %}</td> <td>{% trans %}From{% endtrans %}</td>
<td>{% trans %}To{% endtrans %}</td> <td>{% trans %}To{% endtrans %}</td>
</thead> </thead>
<tbody> <tbody>
{% for m in club.members.exclude(end_date=None).order_by('-role', 'description', '-end_date').all() %} {% for m in club.members.exclude(end_date=None).order_by('-role', 'description', '-end_date').all() %}
<tr> <tr>
<td>{{ user_profile_link(m.user) }}</td> <td>{{ user_profile_link(m.user) }}</td>
<td>{{ settings.SITH_CLUB_ROLES[m.role] }}</td> <td>{{ settings.SITH_CLUB_ROLES[m.role] }}</td>
<td>{{ m.description }}</td> <td>{{ m.description }}</td>
<td>{{ m.start_date }}</td> <td>{{ m.start_date }}</td>
<td>{{ m.end_date }}</td> <td>{{ m.end_date }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% endblock %} {% endblock %}

View File

@ -2,65 +2,65 @@
{% from 'core/macros.jinja' import user_profile_link, paginate %} {% from 'core/macros.jinja' import user_profile_link, paginate %}
{% block content %} {% block content %}
<h3>{% trans %}Sales{% endtrans %}</h3> <h3>{% trans %}Sales{% endtrans %}</h3>
<form id="form" action="?page=1" method="post"> <form id="form" action="?page=1" method="post">
{% csrf_token %} {% csrf_token %}
{{ form }} {{ form }}
<p><input type="submit" value="{% trans %}Show{% endtrans %}" /></p> <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> <p><input type="submit" value="{% trans %}Download as cvs{% endtrans %}" formaction="{{ url('club:sellings_csv', club_id=object.id) }}"/></p>
</form> </form>
<p> <p>
{% trans %}Quantity: {% endtrans %}{{ total_quantity }} {% trans %}units{% endtrans %}<br/> {% trans %}Quantity: {% endtrans %}{{ total_quantity }} {% trans %}units{% endtrans %}<br/>
{% trans %}Total: {% endtrans %}{{ total }} €<br/> {% trans %}Total: {% endtrans %}{{ total }} €<br/>
{% trans %}Benefit: {% endtrans %}{{ benefit }} {% trans %}Benefit: {% endtrans %}{{ benefit }}
</p> </p>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Date{% endtrans %}</td> <td>{% trans %}Date{% endtrans %}</td>
<td>{% trans %}Counter{% endtrans %}</td> <td>{% trans %}Counter{% endtrans %}</td>
<td>{% trans %}Barman{% endtrans %}</td> <td>{% trans %}Barman{% endtrans %}</td>
<td>{% trans %}Customer{% endtrans %}</td> <td>{% trans %}Customer{% endtrans %}</td>
<td>{% trans %}Label{% endtrans %}</td> <td>{% trans %}Label{% endtrans %}</td>
<td>{% trans %}Quantity{% endtrans %}</td> <td>{% trans %}Quantity{% endtrans %}</td>
<td>{% trans %}Total{% endtrans %}</td> <td>{% trans %}Total{% endtrans %}</td>
<td>{% trans %}Payment method{% endtrans %}</td> <td>{% trans %}Payment method{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for s in paginated_result %} {% for s in paginated_result %}
<tr> <tr>
<td>{{ s.date|localtime|date(DATETIME_FORMAT) }} {{ s.date|localtime|time(DATETIME_FORMAT) }}</td> <td>{{ s.date|localtime|date(DATETIME_FORMAT) }} {{ s.date|localtime|time(DATETIME_FORMAT) }}</td>
<td>{{ s.counter }}</td> <td>{{ s.counter }}</td>
{% if s.seller %} {% if s.seller %}
<td><a href="{{ s.seller.get_absolute_url() }}">{{ s.seller.get_display_name() }}</a></td> <td><a href="{{ s.seller.get_absolute_url() }}">{{ s.seller.get_display_name() }}</a></td>
{% else %} {% else %}
<td></td> <td></td>
{% endif %} {% endif %}
{% if s.customer %} {% if s.customer %}
<td><a href="{{ s.customer.user.get_absolute_url() }}">{{ s.customer.user.get_display_name() }}</a></td> <td><a href="{{ s.customer.user.get_absolute_url() }}">{{ s.customer.user.get_display_name() }}</a></td>
{% else %} {% else %}
<td></td> <td></td>
{% endif %} {% endif %}
<td>{{ s.label }}</td> <td>{{ s.label }}</td>
<td>{{ s.quantity }}</td> <td>{{ s.quantity }}</td>
<td>{{ s.quantity * s.unit_price }} €</td> <td>{{ s.quantity * s.unit_price }} €</td>
<td>{{ s.get_payment_method_display() }}</td> <td>{{ s.get_payment_method_display() }}</td>
{% if s.is_owned_by(user) %} {% if s.is_owned_by(user) %}
<td><a href="{{ url('counter:selling_delete', selling_id=s.id) }}">{% trans %}Delete{% endtrans %}</a></td> <td><a href="{{ url('counter:selling_delete', selling_id=s.id) }}">{% trans %}Delete{% endtrans %}</a></td>
{% endif %} {% endif %}
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<script type="text/javascript"> <script type="text/javascript">
function formPagination(link){ function formPagination(link){
$("form").attr("action", link.href); $("form").attr("action", link.href);
link.href = "javascript:void(0)"; // block link action link.href = "javascript:void(0)"; // block link action
$("form").submit(); $("form").submit();
} }
</script> </script>
{{ paginate(paginated_result, paginator, "formPagination(this)") }} {{ paginate(paginated_result, paginator, "formPagination(this)") }}
{% endblock %} {% endblock %}

View File

@ -1,46 +1,46 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block content %} {% block content %}
<h3>{% trans %}Club tools{% endtrans %}</h3> <h3>{% trans %}Club tools{% endtrans %}</h3>
<div> <div>
<h4>{% trans %}Communication:{% endtrans %}</h4> <h4>{% trans %}Communication:{% endtrans %}</h4>
<ul> <ul>
<li> <a href="{{ url('com:news_new') }}?club={{ object.id }}">{% trans %}Create a news{% endtrans %}</a></li> <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> <li> <a href="{{ url('com:weekmail_article') }}?club={{ object.id }}">{% trans %}Post in the Weekmail{% endtrans %}</a></li>
{% if object.trombi %} {% if object.trombi %}
<li> <a href="{{ url('trombi:detail', trombi_id=object.trombi.id) }}">{% trans %}Edit Trombi{% endtrans %}</a></li> <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('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> <li> <a href="{{ url('club:poster_list', club_id=object.id) }}">{% trans %}Posters{% endtrans %}</a></li>
{% endif %} {% endif %}
</ul> </ul>
<h4>{% trans %}Counters:{% endtrans %}</h4> <h4>{% trans %}Counters:{% endtrans %}</h4>
<ul> <ul>
{% if object.unix_name == settings.SITH_LAUNDERETTE_MANAGER['unix_name'] %} {% if object.unix_name == settings.SITH_LAUNDERETTE_MANAGER['unix_name'] %}
{% for l in Launderette.objects.all() %} {% for l in Launderette.objects.all() %}
<li><a href="{{ url('launderette:main_click', launderette_id=l.id) }}">{{ l }}</a></li> <li><a href="{{ url('launderette:main_click', launderette_id=l.id) }}">{{ l }}</a></li>
{% endfor %} {% endfor %}
{% elif object.counters.filter(type="OFFICE")|count > 0 %} {% elif object.counters.filter(type="OFFICE")|count > 0 %}
{% for c in object.counters.filter(type="OFFICE") %} {% 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:details', counter_id=c.id) }}">View</a>
<a href="{{ url('counter:admin', counter_id=c.id) }}">Edit</a> <a href="{{ url('counter:admin', counter_id=c.id) }}">Edit</a>
</li> </li>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</ul> </ul>
{% if object.club_account.exists() %} {% if object.club_account.exists() %}
<h4>{% trans %}Accounting: {% endtrans %}</h4> <h4>{% trans %}Accounting: {% endtrans %}</h4>
<ul> <ul>
{% for ca in object.club_account.all() %} {% 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 %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
{% if object.unix_name == settings.SITH_LAUNDERETTE_MANAGER['unix_name'] %} {% 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 %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -2,107 +2,107 @@
{% from 'core/macros.jinja' import select_all_checkbox %} {% from 'core/macros.jinja' import select_all_checkbox %}
{% block title %} {% block title %}
{% trans %}Mailing lists{% endtrans %} {% trans %}Mailing lists{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% 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 %} {% if mailings_not_moderated %}
<p>{% trans %}Mailing lists waiting for moderation{% endtrans %}</p> <p>{% trans %}Mailing lists waiting for moderation{% endtrans %}</p>
<ul> <ul>
{% for mailing in mailings_not_moderated %} {% 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> <li>{{ mailing.email_full }}<a href="{{ url('club:mailing_delete', mailing_id=mailing.id) }}"> - {% trans %}Delete{% endtrans %}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
{% if mailings_moderated %} {% if mailings_moderated %}
{% for mailing in 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) -%} {%- 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 -%} {%- endif -%}
</h2> </h2>
<form method="GET" action="{{ url('club:mailing_generate', mailing_id=mailing.id) }}" style="display:inline-block;"> <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 %}"> <input type="submit" name="generateMalingList" value="{% trans %}Generate mailing list{% endtrans %}">
</form> </form>
{% set form_mailing_removal = form["removal_" + mailing.id|string] %} {% set form_mailing_removal = form["removal_" + mailing.id|string] %}
{% if form_mailing_removal.field.choices %} {% if form_mailing_removal.field.choices %}
{% set ms = dict(mailing.subscriptions.all() | groupby('id')) %} {% 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"> <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> <p style="margin-bottom: 1em;">{{ select_all_checkbox(form_mailing_removal.auto_id) }}</p>
{% csrf_token %} {% csrf_token %}
<input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.REMOVE_SUBSCRIPTION }}" /> <input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.REMOVE_SUBSCRIPTION }}" />
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}User{% endtrans %}</td> <td>{% trans %}User{% endtrans %}</td>
<td>{% trans %}Email{% endtrans %}</td> <td>{% trans %}Email{% endtrans %}</td>
<td>{% trans %}Delete{% endtrans %}</td> <td>{% trans %}Delete{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for widget in form_mailing_removal.subwidgets %} {% for widget in form_mailing_removal.subwidgets %}
{% set user = ms[widget.data.value.value][0] %} {% set user = ms[widget.data.value.value][0] %}
<tr> <tr>
<td>{{ user.get_username }}</td> <td>{{ user.get_username }}</td>
<td>{{ user.get_email }}</td> <td>{{ user.get_email }}</td>
<td>{{ widget.tag() }}</td> <td>{{ widget.tag() }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{{ form_mailing_removal.errors }} {{ form_mailing_removal.errors }}
<p><input type="submit" value="{% trans %}Remove from mailing list{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Remove from mailing list{% endtrans %}" /></p>
</form> </form>
{% else %} {% else %}
<p><b>{% trans %}There is no subscriber for this mailing list{% endtrans %}</b></p> <p><b>{% trans %}There is no subscriber for this mailing list{% endtrans %}</b></p>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% else %} {% else %}
<p>{% trans %}No mailing list existing for this club{% endtrans %}</p> <p>{% trans %}No mailing list existing for this club{% endtrans %}</p>
{% endif %} {% endif %}
<p>{{ form.non_field_errors() }}</p> <p>{{ form.non_field_errors() }}</p>
{% if mailings_moderated %} {% if mailings_moderated %}
<h2>{% trans %}New member{% endtrans %}</h2> <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>
<form action="{{ url('club:mailing', club_id=club.id) }}" method="post" enctype="multipart/form-data"> <form action="{{ url('club:mailing', club_id=club.id) }}" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
<p> <p>
{{ form.mailing_email.errors }} {{ form.subscription_mailing.errors }}
<label for="{{ form.mailing_email.id_for_label }}">{{ form.mailing_email.label }}</label> <label for="{{ form.subscription_mailing.id_for_label }}">{{ form.subscription_mailing.label }}</label>
{{ form.mailing_email }} {{ form.subscription_mailing }}
</p> </p>
<input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.NEW_MALING }}" /> <p>
<p><input type="submit" value="{% trans %}Create mailing list{% endtrans %}" /></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> </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 %} {% endblock %}

View File

@ -2,11 +2,11 @@
{% from 'core/macros_pages.jinja' import page_history %} {% from 'core/macros_pages.jinja' import page_history %}
{% block content %} {% block content %}
{% if club.page %} {% if club.page %}
{{ page_history(club.page) }} {{ page_history(club.page) }}
{% else %} {% else %}
{% trans %}No page existing for this club{% endtrans %} {% trans %}No page existing for this club{% endtrans %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -2,7 +2,7 @@
{% from 'core/macros_pages.jinja' import page_edit_form %} {% from 'core/macros_pages.jinja' import page_edit_form %}
{% block content %} {% 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 %} {% endblock %}

View File

@ -1,48 +1,48 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Club stats{% endtrans %} {% trans %}Club stats{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% if club_list %} {% if club_list %}
<h3>{% trans %}Club stats{% endtrans %}</h3> <h3>{% trans %}Club stats{% endtrans %}</h3>
<form action="" method="GET"> <form action="" method="GET">
{% csrf_token %} {% csrf_token %}
<p> <p>
<select name="branch"> <select name="branch">
{% for b in settings.SITH_PROFILE_DEPARTMENTS %} {% for b in settings.SITH_PROFILE_DEPARTMENTS %}
<option value="{{ b[0] }}">{{ b[0] }}</option> <option value="{{ b[0] }}">{{ b[0] }}</option>
{% endfor %} {% endfor %}
</select> </select>
</p> </p>
<p><input type="submit" value="{% trans %}Show{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Show{% endtrans %}" /></p>
</form> </form>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>Club</td> <td>Club</td>
<td>Member number</td> <td>Member number</td>
<td>Old member number</td> <td>Old member number</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for c in club_list.order_by('id') %} {% for c in club_list.order_by('id') %}
{% set members = c.members.all() %} {% set members = c.members.all() %}
{% if request.GET['branch'] %} {% if request.GET['branch'] %}
{% set members = members.filter(user__department=request.GET['branch']) %} {% set members = members.filter(user__department=request.GET['branch']) %}
{% endif %} {% endif %}
<tr> <tr>
<td>{{ c.get_display_name() }}</td> <td>{{ c.get_display_name() }}</td>
<td>{{ members.filter(end_date=None, role__gt=settings.SITH_MAXIMUM_FREE_ROLE).count() }}</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> <td>{{ members.exclude(end_date=None, role__gt=settings.SITH_MAXIMUM_FREE_ROLE).count() }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% else %} {% else %}
{% trans %}There is no club in this website.{% endtrans %} {% trans %}There is no club in this website.{% endtrans %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -1,43 +1,43 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Mailing lists administration{% endtrans %} {% trans %}Mailing lists administration{% endtrans %}
{% endblock %} {% endblock %}
{% macro display_mailings(list) %} {% macro display_mailings(list) %}
<table> <table>
<tr> <tr>
<th>{% trans %}Email{% endtrans %}</th> <th>{% trans %}Email{% endtrans %}</th>
<th>{% trans %}Club{%endtrans%}</th> <th>{% trans %}Club{%endtrans%}</th>
<th>{% trans %}Actions{% endtrans %}</th> <th>{% trans %}Actions{% endtrans %}</th>
</tr> </tr>
{% for mailing in list %} {% for mailing in list %}
<tr> <tr>
<td>{{ mailing.email_full }}</td> <td>{{ mailing.email_full }}</td>
<td><a href="{{ url('club:mailing', club_id=mailing.club.id) }}">{{ mailing.club }}</a></td> <td><a href="{{ url('club:mailing', club_id=mailing.club.id) }}">{{ mailing.club }}</a></td>
<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 %} <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> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
{% endmacro %} {% endmacro %}
{% block content %} {% 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> <h2>{% trans %}Not moderated mailing lists{% endtrans %}</h2>
{{ display_mailings(unmoderated) }} {{ display_mailings(unmoderated) }}
{% endif %} {% endif %}
<h2>{% trans %}Moderated mailing lists{% endtrans %}</h2> <h2>{% trans %}Moderated mailing lists{% endtrans %}</h2>
{% if has_moderated %} {% if has_moderated %}
{{ display_mailings(moderated) }} {{ display_mailings(moderated) }}
{% else %} {% else %}
<p>{% trans %}No mailing list existing{% endtrans %}</p> <p>{% trans %}No mailing list existing{% endtrans %}</p>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -2,317 +2,317 @@
{% from 'core/macros.jinja' import user_profile_link %} {% from 'core/macros.jinja' import user_profile_link %}
{% block title %} {% block title %}
{% trans %}News admin{% endtrans %} {% trans %}News admin{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% 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 /> <hr />
<h4>{% trans %}Notices{% endtrans %}</h4> <h4>{% trans %}Notices{% endtrans %}</h4>
{% set notices = object_list.filter(type="NOTICE").distinct().order_by('id') %} {% set notices = object_list.filter(type="NOTICE").distinct().order_by('id') %}
<h5>{% trans %}Displayed notices{% endtrans %}</h5> <h5>{% trans %}Displayed notices{% endtrans %}</h5>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Type{% endtrans %}</td> <td>{% trans %}Type{% endtrans %}</td>
<td>{% trans %}Title{% endtrans %}</td> <td>{% trans %}Title{% endtrans %}</td>
<td>{% trans %}Summary{% endtrans %}</td> <td>{% trans %}Summary{% endtrans %}</td>
<td>{% trans %}Club{% endtrans %}</td> <td>{% trans %}Club{% endtrans %}</td>
<td>{% trans %}Author{% endtrans %}</td> <td>{% trans %}Author{% endtrans %}</td>
<td>{% trans %}Moderator{% endtrans %}</td> <td>{% trans %}Moderator{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for news in notices.filter(is_moderated=True) %} {% for news in notices.filter(is_moderated=True) %}
<tr> <tr>
<td>{{ news.get_type_display() }}</td> <td>{{ news.get_type_display() }}</td>
<td>{{ news.title }}</td> <td>{{ news.title }}</td>
<td>{{ news.summary|markdown }}</td> <td>{{ news.summary|markdown }}</td>
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></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.author) }}</td>
<td>{{ user_profile_link(news.moderator) }}</td> <td>{{ user_profile_link(news.moderator) }}</td>
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a> <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_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_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<h5>{% trans %}Notices to moderate{% endtrans %}</h5> <h5>{% trans %}Notices to moderate{% endtrans %}</h5>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Type{% endtrans %}</td> <td>{% trans %}Type{% endtrans %}</td>
<td>{% trans %}Title{% endtrans %}</td> <td>{% trans %}Title{% endtrans %}</td>
<td>{% trans %}Summary{% endtrans %}</td> <td>{% trans %}Summary{% endtrans %}</td>
<td>{% trans %}Club{% endtrans %}</td> <td>{% trans %}Club{% endtrans %}</td>
<td>{% trans %}Author{% endtrans %}</td> <td>{% trans %}Author{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for news in notices.filter(is_moderated=False) %} {% for news in notices.filter(is_moderated=False) %}
<tr> <tr>
<td>{{ news.get_type_display() }}</td> <td>{{ news.get_type_display() }}</td>
<td>{{ news.title }}</td> <td>{{ news.title }}</td>
<td>{{ news.summary|markdown }}</td> <td>{{ news.summary|markdown }}</td>
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></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.author) }}</td>
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a> <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_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_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<hr /> <hr />
<h4>{% trans %}Weeklies{% endtrans %}</h4> <h4>{% trans %}Weeklies{% endtrans %}</h4>
{% set weeklies = object_list.filter(type="WEEKLY", dates__end_date__gte=timezone.now()).distinct().order_by('id') %} {% set weeklies = object_list.filter(type="WEEKLY", dates__end_date__gte=timezone.now()).distinct().order_by('id') %}
<h5>{% trans %}Displayed weeklies{% endtrans %}</h5> <h5>{% trans %}Displayed weeklies{% endtrans %}</h5>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Type{% endtrans %}</td> <td>{% trans %}Type{% endtrans %}</td>
<td>{% trans %}Title{% endtrans %}</td> <td>{% trans %}Title{% endtrans %}</td>
<td>{% trans %}Summary{% endtrans %}</td> <td>{% trans %}Summary{% endtrans %}</td>
<td>{% trans %}Club{% endtrans %}</td> <td>{% trans %}Club{% endtrans %}</td>
<td>{% trans %}Author{% endtrans %}</td> <td>{% trans %}Author{% endtrans %}</td>
<td>{% trans %}Moderator{% endtrans %}</td> <td>{% trans %}Moderator{% endtrans %}</td>
<td>{% trans %}Dates{% endtrans %}</td> <td>{% trans %}Dates{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for news in weeklies.filter(is_moderated=True) %} {% for news in weeklies.filter(is_moderated=True) %}
<tr> <tr>
<td>{{ news.get_type_display() }}</td> <td>{{ news.get_type_display() }}</td>
<td>{{ news.title }}</td> <td>{{ news.title }}</td>
<td>{{ news.summary|markdown }}</td> <td>{{ news.summary|markdown }}</td>
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></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.author) }}</td>
<td>{{ user_profile_link(news.moderator) }}</td> <td>{{ user_profile_link(news.moderator) }}</td>
<td> <td>
<ul> <ul>
{% for d in news.dates.all() %} {% for d in news.dates.all() %}
<li>{{ d.start_date|localtime|date(DATETIME_FORMAT) }} <li>{{ d.start_date|localtime|date(DATETIME_FORMAT) }}
{{ d.start_date|localtime|time(DATETIME_FORMAT) }} - {{ d.start_date|localtime|time(DATETIME_FORMAT) }} -
{{ d.end_date|localtime|date(DATETIME_FORMAT) }} {{ d.end_date|localtime|date(DATETIME_FORMAT) }}
{{ d.end_date|localtime|time(DATETIME_FORMAT) }} {{ d.end_date|localtime|time(DATETIME_FORMAT) }}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
</td> </td>
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a> <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_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_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<h5>{% trans %}Weeklies to moderate{% endtrans %}</h5> <h5>{% trans %}Weeklies to moderate{% endtrans %}</h5>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Type{% endtrans %}</td> <td>{% trans %}Type{% endtrans %}</td>
<td>{% trans %}Title{% endtrans %}</td> <td>{% trans %}Title{% endtrans %}</td>
<td>{% trans %}Summary{% endtrans %}</td> <td>{% trans %}Summary{% endtrans %}</td>
<td>{% trans %}Club{% endtrans %}</td> <td>{% trans %}Club{% endtrans %}</td>
<td>{% trans %}Author{% endtrans %}</td> <td>{% trans %}Author{% endtrans %}</td>
<td>{% trans %}Dates{% endtrans %}</td> <td>{% trans %}Dates{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for news in weeklies.filter(is_moderated=False) %} {% for news in weeklies.filter(is_moderated=False) %}
<tr> <tr>
<td>{{ news.get_type_display() }}</td> <td>{{ news.get_type_display() }}</td>
<td>{{ news.title }}</td> <td>{{ news.title }}</td>
<td>{{ news.summary|markdown }}</td> <td>{{ news.summary|markdown }}</td>
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></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.author) }}</td>
<td> <td>
<ul> <ul>
{% for d in news.dates.all() %} {% for d in news.dates.all() %}
<li>{{ d.start_date|localtime|date(DATETIME_FORMAT) }} <li>{{ d.start_date|localtime|date(DATETIME_FORMAT) }}
{{ d.start_date|localtime|time(DATETIME_FORMAT) }} - {{ d.start_date|localtime|time(DATETIME_FORMAT) }} -
{{ d.end_date|localtime|date(DATETIME_FORMAT) }} {{ d.end_date|localtime|date(DATETIME_FORMAT) }}
{{ d.end_date|localtime|time(DATETIME_FORMAT) }} {{ d.end_date|localtime|time(DATETIME_FORMAT) }}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
</td> </td>
<td><a href="{{ url('com:news_detail', news_id=news.id) }}">{% trans %}View{% endtrans %}</a> <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_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_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<hr /> <hr />
<h4>{% trans %}Calls{% endtrans %}</h4> <h4>{% trans %}Calls{% endtrans %}</h4>
{% set calls = object_list.filter(type="CALL", dates__end_date__gte=timezone.now()).distinct().order_by('id') %} {% set calls = object_list.filter(type="CALL", dates__end_date__gte=timezone.now()).distinct().order_by('id') %}
<h5>{% trans %}Displayed calls{% endtrans %}</h5> <h5>{% trans %}Displayed calls{% endtrans %}</h5>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Type{% endtrans %}</td> <td>{% trans %}Type{% endtrans %}</td>
<td>{% trans %}Title{% endtrans %}</td> <td>{% trans %}Title{% endtrans %}</td>
<td>{% trans %}Summary{% endtrans %}</td> <td>{% trans %}Summary{% endtrans %}</td>
<td>{% trans %}Club{% endtrans %}</td> <td>{% trans %}Club{% endtrans %}</td>
<td>{% trans %}Author{% endtrans %}</td> <td>{% trans %}Author{% endtrans %}</td>
<td>{% trans %}Moderator{% endtrans %}</td> <td>{% trans %}Moderator{% endtrans %}</td>
<td>{% trans %}Start{% endtrans %}</td> <td>{% trans %}Start{% endtrans %}</td>
<td>{% trans %}End{% endtrans %}</td> <td>{% trans %}End{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for news in calls.filter(is_moderated=True) %} {% for news in calls.filter(is_moderated=True) %}
<tr> <tr>
<td>{{ news.get_type_display() }}</td> <td>{{ news.get_type_display() }}</td>
<td>{{ news.title }}</td> <td>{{ news.title }}</td>
<td>{{ news.summary|markdown }}</td> <td>{{ news.summary|markdown }}</td>
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></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.author) }}</td>
<td>{{ user_profile_link(news.moderator) }}</td> <td>{{ user_profile_link(news.moderator) }}</td>
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} <td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td> {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }} <td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td> {{ 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> <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_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_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<h5>{% trans %}Calls to moderate{% endtrans %}</h5> <h5>{% trans %}Calls to moderate{% endtrans %}</h5>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Type{% endtrans %}</td> <td>{% trans %}Type{% endtrans %}</td>
<td>{% trans %}Title{% endtrans %}</td> <td>{% trans %}Title{% endtrans %}</td>
<td>{% trans %}Summary{% endtrans %}</td> <td>{% trans %}Summary{% endtrans %}</td>
<td>{% trans %}Club{% endtrans %}</td> <td>{% trans %}Club{% endtrans %}</td>
<td>{% trans %}Author{% endtrans %}</td> <td>{% trans %}Author{% endtrans %}</td>
<td>{% trans %}Start{% endtrans %}</td> <td>{% trans %}Start{% endtrans %}</td>
<td>{% trans %}End{% endtrans %}</td> <td>{% trans %}End{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for news in calls.filter(is_moderated=False) %} {% for news in calls.filter(is_moderated=False) %}
<tr> <tr>
<td>{{ news.get_type_display() }}</td> <td>{{ news.get_type_display() }}</td>
<td>{{ news.title }}</td> <td>{{ news.title }}</td>
<td>{{ news.summary|markdown }}</td> <td>{{ news.summary|markdown }}</td>
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></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.author) }}</td>
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} <td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td> {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }} <td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td> {{ 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> <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_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_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<hr /> <hr />
<h4>{% trans %}Events{% endtrans %}</h4> <h4>{% trans %}Events{% endtrans %}</h4>
{% set events = object_list.filter(type="EVENT", dates__end_date__gte=timezone.now()).distinct().order_by('id') %} {% set events = object_list.filter(type="EVENT", dates__end_date__gte=timezone.now()).distinct().order_by('id') %}
<h5>{% trans %}Displayed events{% endtrans %}</h5> <h5>{% trans %}Displayed events{% endtrans %}</h5>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Type{% endtrans %}</td> <td>{% trans %}Type{% endtrans %}</td>
<td>{% trans %}Title{% endtrans %}</td> <td>{% trans %}Title{% endtrans %}</td>
<td>{% trans %}Summary{% endtrans %}</td> <td>{% trans %}Summary{% endtrans %}</td>
<td>{% trans %}Club{% endtrans %}</td> <td>{% trans %}Club{% endtrans %}</td>
<td>{% trans %}Author{% endtrans %}</td> <td>{% trans %}Author{% endtrans %}</td>
<td>{% trans %}Moderator{% endtrans %}</td> <td>{% trans %}Moderator{% endtrans %}</td>
<td>{% trans %}Start{% endtrans %}</td> <td>{% trans %}Start{% endtrans %}</td>
<td>{% trans %}End{% endtrans %}</td> <td>{% trans %}End{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for news in events.filter(is_moderated=True) %} {% for news in events.filter(is_moderated=True) %}
<tr> <tr>
<td>{{ news.get_type_display() }}</td> <td>{{ news.get_type_display() }}</td>
<td>{{ news.title }}</td> <td>{{ news.title }}</td>
<td>{{ news.summary|markdown }}</td> <td>{{ news.summary|markdown }}</td>
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></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.author) }}</td>
<td>{{ user_profile_link(news.moderator) }}</td> <td>{{ user_profile_link(news.moderator) }}</td>
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} <td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td> {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }} <td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td> {{ 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> <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_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_moderate', news_id=news.id) }}?remove">{% trans %}Remove{% endtrans %}</a>
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<h5>{% trans %}Events to moderate{% endtrans %}</h5> <h5>{% trans %}Events to moderate{% endtrans %}</h5>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Type{% endtrans %}</td> <td>{% trans %}Type{% endtrans %}</td>
<td>{% trans %}Title{% endtrans %}</td> <td>{% trans %}Title{% endtrans %}</td>
<td>{% trans %}Summary{% endtrans %}</td> <td>{% trans %}Summary{% endtrans %}</td>
<td>{% trans %}Club{% endtrans %}</td> <td>{% trans %}Club{% endtrans %}</td>
<td>{% trans %}Author{% endtrans %}</td> <td>{% trans %}Author{% endtrans %}</td>
<td>{% trans %}Start{% endtrans %}</td> <td>{% trans %}Start{% endtrans %}</td>
<td>{% trans %}End{% endtrans %}</td> <td>{% trans %}End{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for news in events.filter(is_moderated=False) %} {% for news in events.filter(is_moderated=False) %}
<tr> <tr>
<td>{{ news.get_type_display() }}</td> <td>{{ news.get_type_display() }}</td>
<td>{{ news.title }}</td> <td>{{ news.title }}</td>
<td>{{ news.summary|markdown }}</td> <td>{{ news.summary|markdown }}</td>
<td><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></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.author) }}</td>
<td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} <td>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td> {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</td>
<td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }} <td>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</td> {{ 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> <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_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_moderate', news_id=news.id) }}">{% trans %}Moderate{% endtrans %}</a>
<a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url('com:news_delete', news_id=news.id) }}">{% trans %}Delete{% endtrans %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% endblock %} {% endblock %}

View File

@ -2,48 +2,48 @@
{% from 'core/macros.jinja' import user_profile_link, facebook_share, tweet, link_news_logo, gen_news_metatags %} {% from 'core/macros.jinja' import user_profile_link, facebook_share, tweet, link_news_logo, gen_news_metatags %}
{% block title %} {% block title %}
{% trans %}News{% endtrans %} - {% trans %}News{% endtrans %} -
{{ object.title }} {{ object.title }}
{% endblock %} {% endblock %}
{% block head %} {% block head %}
{{ super() }} {{ super() }}
{{ gen_news_metatags(news) }} {{ gen_news_metatags(news) }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<p><a href="{{ url('com:news_list') }}">{% trans %}Back to news{% endtrans %}</a></p> <p><a href="{{ url('com:news_list') }}">{% trans %}Back to news{% endtrans %}</a></p>
<section id="news_details"> <section id="news_details">
<div class="club_logo"> <div class="club_logo">
<img src="{{ link_news_logo(news)}}" alt="{{ news.club }}" /> <img src="{{ link_news_logo(news)}}" alt="{{ news.club }}" />
<a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a> <a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a>
</div> </div>
<h4>{{ news.title }}</h4> <h4>{{ news.title }}</h4>
<p class="date"> <p class="date">
<span>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} <span>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> - {{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
<span>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }} <span>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span> {{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
</p> </p>
<div class="news_content"> <div class="news_content">
<div><em>{{ news.summary|markdown }}</em></div> <div><em>{{ news.summary|markdown }}</em></div>
<br/> <br/>
<div>{{ news.content|markdown }}</div> <div>{{ news.content|markdown }}</div>
{{ facebook_share(news) }} {{ facebook_share(news) }}
{{ tweet(news) }} {{ tweet(news) }}
<div class="news_meta"> <div class="news_meta">
<p>{% trans %}Author: {% endtrans %}{{ user_profile_link(news.author) }}</p> <p>{% trans %}Author: {% endtrans %}{{ user_profile_link(news.author) }}</p>
{% if news.moderator %} {% 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 %} {% 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 %} {% endif %}
{% if user.can_edit(news) %} {% 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 %} {% endif %}
</div> </div>
</div> </div>
</section> </section>
{% endblock %} {% endblock %}

View File

@ -2,46 +2,46 @@
{% from 'core/macros.jinja' import user_profile_link %} {% from 'core/macros.jinja' import user_profile_link %}
{% block title %} {% block title %}
{% if object %} {% if object %}
{% trans %}Edit news{% endtrans %} {% trans %}Edit news{% endtrans %}
{% else %} {% else %}
{% trans %}Create news{% endtrans %} {% trans %}Create news{% endtrans %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% if 'preview' in request.POST.keys() %} {% if 'preview' in request.POST.keys() %}
<section class="news_event"> <section class="news_event">
<h4>{{ form.instance.title }}</h4> <h4>{{ form.instance.title }}</h4>
<p class="date"> <p class="date">
<span>{{ form.instance.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} <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) }} <span>{{ form.instance.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
{{ form.instance.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span> {{ form.instance.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
</p> </p>
<p><a href="#">{{ form.instance.club or "Club" }}</a></p> <p><a href="#">{{ form.instance.club or "Club" }}</a></p>
<div>{{ form.instance.summary|markdown }}</div> <div>{{ form.instance.summary|markdown }}</div>
<div>{{ form.instance.content|markdown }}</div> <div>{{ form.instance.content|markdown }}</div>
<p>{% trans %}Author: {% endtrans %} {{ user_profile_link(form.instance.author) }}</p> <p>{% trans %}Author: {% endtrans %} {{ user_profile_link(form.instance.author) }}</p>
</section> </section>
{% endif %} {% endif %}
{% if object %} {% if object %}
<h2>{% trans %}Edit news{% endtrans %}</h2> <h2>{% trans %}Edit news{% endtrans %}</h2>
{% else %} {% else %}
<h2>{% trans %}Create news{% endtrans %}</h2> <h2>{% trans %}Create news{% endtrans %}</h2>
{% endif %} {% endif %}
<form action="" method="post"> <form action="" method="post">
{% csrf_token %} {% csrf_token %}
{{ form.non_field_errors() }} {{ form.non_field_errors() }}
{{ form.author }} {{ form.author }}
<p>{{ form.type.errors }}<label for="{{ form.type.name }}">{{ form.type.label }}</label> <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 %}Notice: Information, election result - no date{% endtrans %}</li>
<li>{% trans %}Event: punctual event, associated with one 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 %}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> <li>{% trans %}Call: long time event, associated with a long date (election appliance, ...){% endtrans %}</li>
</ul> </ul>
{{ form.type }}</p> {{ 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.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="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> <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.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> <p>{{ form.content.errors }}<label for="{{ form.content.name }}">{{ form.content.label }}</label> {{ form.content }}</p>
{% if user.is_com_admin %} {% 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> {{ form.automoderation }}</p>
{% endif %} {% endif %}
<p><input type="submit" name="preview" value="{% trans %}Preview{% endtrans %}" /></p> <p><input type="submit" name="preview" value="{% trans %}Preview{% endtrans %}" /></p>
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form> </form>
{% endblock %} {% endblock %}
{% block script %} {% block script %}
{{ super() }} {{ super() }}
<script> <script>
$( function() { $( function() {
var type = $('input[name=type]'); var type = $('input[name=type]');
var dates = $('.date'); var dates = $('.date');
var until = $('.until'); var until = $('.until');
function update_targets () { function update_targets () {
type_checked = $('input[name=type]:checked'); type_checked = $('input[name=type]:checked');
if (type_checked.val() == "EVENT" || type_checked.val() == "CALL") { if (type_checked.val() == "EVENT" || type_checked.val() == "CALL") {
dates.show(); dates.show();
until.hide(); until.hide();
} else if (type_checked.val() == "WEEKLY") { } else if (type_checked.val() == "WEEKLY") {
dates.show(); dates.show();
until.show(); until.show();
} else { } else {
dates.hide(); dates.hide();
until.hide(); until.hide();
}
} }
update_targets(); }
type.change(update_targets); update_targets();
} ); type.change(update_targets);
</script> } );
</script>
{% endblock %} {% endblock %}

View File

@ -2,162 +2,162 @@
{% from 'core/macros.jinja' import tweet_quick, fb_quick %} {% from 'core/macros.jinja' import tweet_quick, fb_quick %}
{% block title %} {% block title %}
{% trans %}News{% endtrans %} {% trans %}News{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% if user.is_com_admin %} {% if user.is_com_admin %}
<div id="news_admin"> <div id="news_admin">
<a class="button" href="{{ url('com:news_admin_list') }}">{% trans %}Administrate news{% endtrans %}</a> <a class="button" href="{{ url('com:news_admin_list') }}">{% trans %}Administrate news{% endtrans %}</a>
</div> </div>
<br> <br>
{% endif %} {% endif %}
<div id="news"> <div id="news">
<div id="left_column" class="news_column"> <div id="left_column" class="news_column">
{% for news in object_list.filter(type="NOTICE") %} {% for news in object_list.filter(type="NOTICE") %}
<section class="news_notice"> <section class="news_notice">
<h4><a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a></h4> <h4><a href="{{ url('com:news_detail', news_id=news.id) }}">{{ news.title }}</a></h4>
<div class="news_content">{{ news.summary|markdown }}</div> <div class="news_content">{{ news.summary|markdown }}</div>
</section> </section>
{% endfor %} {% endfor %}
{% for news in object_list.filter(dates__start_date__lte=timezone.now(), dates__end_date__gte=timezone.now(), type="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"> <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> <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"> <div class="news_date">
<span>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }} <span>{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> - <span>{{ news.dates.first().end_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>
<div class="news_content">{{ news.summary|markdown }}</div> <div class="news_content">{{ news.summary|markdown }}
</section> <div class="button_bar">
{{ fb_quick(news) }}
{{ tweet_quick(news) }}
</div>
</div>
</section>
{% endfor %} {% 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>
</div>
{% endfor %}
{% else %}
<div class="news_empty">
<em>{% trans %}Nothing to come...{% endtrans %}</em>
</div>
{% endif %}
<div id="birthdays"> {% set coming_soon = object_list.filter(dates__start_date__gte=timezone.now()+timedelta(days=5),
<div id="birthdays_title">{% trans %}Birthdays{% endtrans %}</div> type="EVENT").order_by('dates__start_date') %}
<div id="birthdays_content"> {% if coming_soon %}
{% if user.is_subscribed %} <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 request for 1 hour #}
{% cache 3600 "birthdays" %} {% cache 3600 "birthdays" %}
<ul class="birthdays_year"> <ul class="birthdays_year">
{% for d in birthdays.dates('date_of_birth', 'year', 'DESC') %} {% for d in birthdays.dates('date_of_birth', 'year', 'DESC') %}
<li> <li>
{% trans age=timezone.now().year - d.year %}{{ age }} year old{% endtrans %} {% trans age=timezone.now().year - d.year %}{{ age }} year old{% endtrans %}
<ul> <ul>
{% for u in birthdays.filter(date_of_birth__year=d.year) %} {% for u in birthdays.filter(date_of_birth__year=d.year) %}
<li><a href="{{ u.get_absolute_url() }}">{{ u.get_short_name() }}</a></li> <li><a href="{{ u.get_absolute_url() }}">{{ u.get_short_name() }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endcache %} {% endcache %}
{% else %} {% else %}
<p>{% trans %}You need an up to date subscription to access this content{% endtrans %}</p> <p>{% trans %}You need an up to date subscription to access this content{% endtrans %}</p>
{% endif %} {% endif %}
</div>
</div>
</div> </div>
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,42 +1,42 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Poster{% endtrans %} {% trans %}Poster{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="poster_edit"> <div id="poster_edit">
<div id="title"> <div id="title">
<div id="links" class="left"> <div id="links" class="left">
{% if app == "com" %} {% if app == "com" %}
<a id="list" class="link" href="{{ url(app + ":poster_list") }}">{% trans %}List{% endtrans %}</a> <a id="list" class="link" href="{{ url(app + ":poster_list") }}">{% trans %}List{% endtrans %}</a>
{% elif app == "club" %} {% elif app == "club" %}
<a id="list" class="link" href="{{ url(app + ":poster_list", club.id) }}">{% trans %}List{% endtrans %}</a> <a id="list" class="link" href="{{ url(app + ":poster_list", club.id) }}">{% trans %}List{% endtrans %}</a>
{% endif %} {% endif %}
</div> </div>
<h3>{% trans %}Posters - edit{% endtrans %}</h3> <h3>{% trans %}Posters - edit{% endtrans %}</h3>
<div id="links" class="right"> <div id="links" class="right">
{% if app == "com" %} {% if app == "com" %}
<a class="link delete" href="{{ url(app + ":poster_delete", poster.id) }}">{% trans %}Delete{% endtrans %}</a> <a class="link delete" href="{{ url(app + ":poster_delete", poster.id) }}">{% trans %}Delete{% endtrans %}</a>
{% elif app == "club" %} {% elif app == "club" %}
<a class="link delete" href="{{ url(app + ":poster_delete", club.id, poster.id) }}">{% trans %}Delete{% endtrans %}</a> <a class="link delete" href="{{ url(app + ":poster_delete", club.id, poster.id) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div id="poster"> <div id="poster">
<form action="" method="post" enctype="multipart/form-data"> <form action="" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{ form.as_p() }} {{ form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form> </form>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,66 +1,66 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block script %} {% block script %}
{{ super() }} {{ super() }}
<script src="{{ static('com/js/poster_list.js') }}"></script> <script src="{{ static('com/js/poster_list.js') }}"></script>
{% endblock %} {% endblock %}
{% block title %} {% block title %}
{% trans %}Poster{% endtrans %} {% trans %}Poster{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="poster_list"> <div id="poster_list">
<div id="title"> <div id="title">
<h3>{% trans %}Posters{% endtrans %}</h3> <h3>{% trans %}Posters{% endtrans %}</h3>
<div id="links" class="right"> <div id="links" class="right">
{% if app == "com" %} {% if app == "com" %}
<a id="create" class="link" href="{{ url(app + ":poster_create") }}">{% trans %}Create{% endtrans %}</a> <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> <a id="moderation" class="link" href="{{ url("com:poster_moderate_list") }}">{% trans %}Moderation{% endtrans %}</a>
{% elif app == "club" %} {% elif app == "club" %}
<a id="create" class="link" href="{{ url(app + ":poster_create", club.id) }}">{% trans %}Create{% endtrans %}</a> <a id="create" class="link" href="{{ url(app + ":poster_create", club.id) }}">{% trans %}Create{% endtrans %}</a>
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div id="posters"> <div id="posters">
{% if poster_list.count() == 0 %} {% if poster_list.count() == 0 %}
<div id="no-posters">{% trans %}No posters{% endtrans %}</div> <div id="no-posters">{% trans %}No posters{% endtrans %}</div>
{% else %} {% else %}
{% for poster in poster_list %} {% for poster in poster_list %}
<div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}"> <div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}">
<div class="name">{{ poster.name }}</div> <div class="name">{{ poster.name }}</div>
<div class="image"><img src="{{ poster.file.url }}"></img></div> <div class="image"><img src="{{ poster.file.url }}"></img></div>
<div class="dates"> <div class="dates">
<div class="begin">{{ poster.date_begin | localtime | date("d/M/Y H:m") }}</div> <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 class="end">{{ poster.date_end | localtime | date("d/M/Y H:m") }}</div>
</div> </div>
{% if app == "com" %} {% if app == "com" %}
<a class="edit" href="{{ url(app + ":poster_edit", poster.id) }}">{% trans %}Edit{% endtrans %}</a> <a class="edit" href="{{ url(app + ":poster_edit", poster.id) }}">{% trans %}Edit{% endtrans %}</a>
{% elif app == "club" %} {% elif app == "club" %}
<a class="edit" href="{{ url(app + ":poster_edit", club.id, poster.id) }}">{% trans %}Edit{% endtrans %}</a> <a class="edit" href="{{ url(app + ":poster_edit", club.id, poster.id) }}">{% trans %}Edit{% endtrans %}</a>
{% endif %} {% endif %}
<div class="tooltip"> <div class="tooltip">
<ul> <ul>
{% for screen in poster.screens.all() %} {% for screen in poster.screens.all() %}
<li>{{ screen }}</li> <li>{{ screen }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</div> </div>
<div id="view"><div id="placeholder"></div></div> <div id="view"><div id="placeholder"></div></div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,39 +1,39 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block script %} {% block script %}
{{ super() }} {{ super() }}
<script src="{{ static('com/js/poster_list.js') }}"></script> <script src="{{ static('com/js/poster_list.js') }}"></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="poster_list"> <div id="poster_list">
<div id="title"> <div id="title">
<div id="links" class="left"> <div id="links" class="left">
<a id="list" class="link" href="{{ url("com:poster_list") }}">{% trans %}List{% endtrans %}</a> <a id="list" class="link" href="{{ url("com:poster_list") }}">{% trans %}List{% endtrans %}</a>
</div> </div>
<h3>{% trans %}Posters - moderation{% endtrans %}</h3> <h3>{% trans %}Posters - moderation{% endtrans %}</h3>
</div> </div>
<div id="posters"> <div id="posters">
{% if object_list.count == 0 %} {% if object_list.count == 0 %}
<div id="no-posters">{% trans %}No objects{% endtrans %}</div> <div id="no-posters">{% trans %}No objects{% endtrans %}</div>
{% else %} {% else %}
{% for poster in object_list %} {% for poster in object_list %}
<div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}"> <div class="poster{% if not poster.is_moderated %} not_moderated{% endif %}">
<div class="name"> {{ poster.name }} </div> <div class="name"> {{ poster.name }} </div>
<div class="image"> <img src="{{ poster.file.url }}"></img> </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> <a class="moderate" href="{{ url("com:poster_moderate", object_id=poster.id) }}">Moderate</a>
</div> </div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</div> </div>
<div id="view"><div id="placeholder"></div></div> <div id="view"><div id="placeholder"></div></div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,33 +1,33 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Screen{% endtrans %} {% trans %}Screen{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="screen_edit"> <div id="screen_edit">
<div id="title"> <div id="title">
<div id="links" class="left"> <div id="links" class="left">
<a id="list" class="link" href="{{ url("com:screen_list") }}">{% trans %}List{% endtrans %}</a> <a id="list" class="link" href="{{ url("com:screen_list") }}">{% trans %}List{% endtrans %}</a>
</div> </div>
<h3>{% trans %}Screen - edit{% endtrans %}</h3> <h3>{% trans %}Screen - edit{% endtrans %}</h3>
<div id="links" class="right"> <div id="links" class="right">
<a class="link delete" href="{{ url("com:screen_delete", screen.id) }}">{% trans %}Delete{% endtrans %}</a> <a class="link delete" href="{{ url("com:screen_delete", screen.id) }}">{% trans %}Delete{% endtrans %}</a>
</div> </div>
</div> </div>
<div id="screen"> <div id="screen">
<form action="" method="post" enctype="multipart/form-data"> <form action="" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{ form.as_p() }} {{ form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form> </form>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,38 +1,38 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Screens{% endtrans %} {% trans %}Screens{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="screen_list"> <div id="screen_list">
<div id="title"> <div id="title">
<h3>{% trans %}Screens{% endtrans %}</h3> <h3>{% trans %}Screens{% endtrans %}</h3>
<div id="links" class="right"> <div id="links" class="right">
<a id="create" class="link" href="{{ url("com:screen_create") }}">{% trans %}Create{% endtrans %}</a> <a id="create" class="link" href="{{ url("com:screen_create") }}">{% trans %}Create{% endtrans %}</a>
</div> </div>
</div> </div>
<div id="screens"> <div id="screens">
{% if screen_list.count() == 0 %} {% if screen_list.count() == 0 %}
<div id="no-screens">{% trans %}No screens{% endtrans %}</div> <div id="no-screens">{% trans %}No screens{% endtrans %}</div>
{% else %} {% else %}
{% for screen in screen_list %} {% for screen in screen_list %}
<div class="screen"> <div class="screen">
<div class="name">{{ screen.name }}</div> <div class="name">{{ screen.name }}</div>
<a class="edit" href="{{ url("com:screen_edit", screen.id) }}">{% trans %}Edit{% endtrans %}</a> <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> <a class="slideshow" href="{{ url("com:screen_slideshow", screen.id) }}" target="_blank">{% trans %}Slideshow{% endtrans %}</a>
</div> </div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,30 +1,30 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="fr"> <html lang="fr">
<head> <head>
<title>{% trans %}Slideshow{% endtrans %}</title> <title>{% trans %}Slideshow{% endtrans %}</title>
<link href="{{ scss('com/slideshow.scss') }}" rel="stylesheet" type="text/css" /> <link href="{{ scss('com/slideshow.scss') }}" rel="stylesheet" type="text/css" />
</head> </head>
<body> <body>
<div id="slideshow"> <div id="slideshow">
<div id="slides"> <div id="slides">
{% for poster in posters %} {% for poster in posters %}
<div class="slide {% if loop.first %}center{% else %}right{% endif %}" display_time="{{ poster.display_time }}"> <div class="slide {% if loop.first %}center{% else %}right{% endif %}" display_time="{{ poster.display_time }}">
<img src="{{ poster.file.url }}"></img> <img src="{{ poster.file.url }}"></img>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
<div id="progress_bullets"> <div id="progress_bullets">
{% for poster in posters %} {% for poster in posters %}
<div class="bullet {% if loop.first %}active{% endif %}"></div> <div class="bullet {% if loop.first %}active{% endif %}"></div>
{% endfor %} {% endfor %}
</div> </div>
<div id="progress_bar"></div> <div id="progress_bar"></div>
</div> </div>
<script src="{{ static('core/js/jquery-3.6.2.min.js') }}"></script> <script src="{{ static('core/js/jquery-3.6.2.min.js') }}"></script>
<script src="{{ static('com/js/slideshow.js') }}"></script> <script src="{{ static('com/js/slideshow.js') }}"></script>
</body> </body>
</html> </html>

View File

@ -2,77 +2,77 @@
{% from 'core/macros.jinja' import user_profile_link %} {% from 'core/macros.jinja' import user_profile_link %}
{% block title %} {% block title %}
{% trans %}Weekmail{% endtrans %} {% trans %}Weekmail{% endtrans %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<h3>{% trans %}Weekmail{% endtrans %} {{ object.id }}</h3> <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') }}">{% 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_preview') }}?send=true">{% trans %}Send{% endtrans %}</a></p>
<p><a href="{{ url('com:weekmail_article') }}">{% trans %}New article{% 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> <h4>{% trans %}Articles in no weekmail yet{% endtrans %}</h4>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Author{% endtrans %}</td> <td>{% trans %}Author{% endtrans %}</td>
<td>{% trans %}Club{% endtrans %}</td> <td>{% trans %}Club{% endtrans %}</td>
<td>{% trans %}Title{% endtrans %}</td> <td>{% trans %}Title{% endtrans %}</td>
<td>{% trans %}Content{% endtrans %}</td> <td>{% trans %}Content{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for a in orphans.all() %} {% for a in orphans.all() %}
<tr> <tr>
<td>{{ user_profile_link(a.author) }}</td> <td>{{ user_profile_link(a.author) }}</td>
<td><a href="{{ a.club.get_absolute_url() }}">{{ a.club }}</a></td> <td><a href="{{ a.club.get_absolute_url() }}">{{ a.club }}</a></td>
<td>{{ a.title }}</td> <td>{{ a.title }}</td>
<td>{{ a.content|markdown }}</td> <td>{{ a.content|markdown }}</td>
<td> <td>
<a href="{{ url('com:weekmail_article_edit', article_id=a.id) }}">{% trans %}Edit{% endtrans %}</a> | <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="{{ 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="?add_article={{ a.id }}">{% trans %}Add to weekmail{% endtrans %}</a> |
<a href="?up_article={{ a.id }}">{% trans %}Up{% endtrans %}</a> | <a href="?up_article={{ a.id }}">{% trans %}Up{% endtrans %}</a> |
<a href="?down_article={{ a.id }}">{% trans %}Down{% endtrans %}</a> <a href="?down_article={{ a.id }}">{% trans %}Down{% endtrans %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<h4>{% trans %}Articles included the next weekmail{% endtrans %}</h4> <h4>{% trans %}Articles included the next weekmail{% endtrans %}</h4>
<table> <table>
<thead> <thead>
<tr> <tr>
<td>{% trans %}Author{% endtrans %}</td> <td>{% trans %}Author{% endtrans %}</td>
<td>{% trans %}Club{% endtrans %}</td> <td>{% trans %}Club{% endtrans %}</td>
<td>{% trans %}Title{% endtrans %}</td> <td>{% trans %}Title{% endtrans %}</td>
<td>{% trans %}Content{% endtrans %}</td> <td>{% trans %}Content{% endtrans %}</td>
<td>{% trans %}Actions{% endtrans %}</td> <td>{% trans %}Actions{% endtrans %}</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for a in object.articles.order_by('rank') %} {% for a in object.articles.order_by('rank') %}
<tr> <tr>
<td>{{ user_profile_link(a.author) }}</td> <td>{{ user_profile_link(a.author) }}</td>
<td><a href="{{ a.club.get_absolute_url() }}">{{ a.club }}</a></td> <td><a href="{{ a.club.get_absolute_url() }}">{{ a.club }}</a></td>
<td>{{ a.title }}</td> <td>{{ a.title }}</td>
<td>{{ a.content|markdown }}</td> <td>{{ a.content|markdown }}</td>
<td> <td>
<a href="{{ url('com:weekmail_article_edit', article_id=a.id) }}">{% trans %}Edit{% endtrans %}</a> | <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="{{ 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="?del_article={{ a.id }}">{% trans %}Delete from weekmail{% endtrans %}</a> |
<a href="?up_article={{ a.id }}">{% trans %}Up{% endtrans %}</a> | <a href="?up_article={{ a.id }}">{% trans %}Up{% endtrans %}</a> |
<a href="?down_article={{ a.id }}">{% trans %}Down{% endtrans %}</a> <a href="?down_article={{ a.id }}">{% trans %}Down{% endtrans %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<form action="" method="post" enctype="multipart/form-data"> <form action="" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{ form.as_p() }} {{ form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -2,41 +2,41 @@
{% from 'core/macros.jinja' import user_profile_link %} {% from 'core/macros.jinja' import user_profile_link %}
{% block title %} {% block title %}
{{ weekmail.title }} {{ weekmail.title }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<a href="{{ url('com:weekmail') }}">{% trans %}Back{% endtrans %}</a> <a href="{{ url('com:weekmail') }}">{% trans %}Back{% endtrans %}</a>
{% if bad_recipients %} {% if bad_recipients %}
<p> <p>
<span class="important"> <span class="important">
{% trans %}The following recipients were refused by the SMTP:{% endtrans %} {% trans %}The following recipients were refused by the SMTP:{% endtrans %}
</span> </span>
<ul> <ul>
{% for r in bad_recipients.keys() %} {% for r in bad_recipients.keys() %}
<li>{{ r }}</li> <li>{{ r }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
</p> </p>
<form method="post" action=""> <form method="post" action="">
{% csrf_token %} {% csrf_token %}
<button type="submit" name="send" value="clean">{% trans %}Clean subscribers{% endtrans %}</button> <button type="submit" name="send" value="clean">{% trans %}Clean subscribers{% endtrans %}</button>
</form> </form>
{% else %} {% else %}
{% if request.GET['send'] %} {% if request.GET['send'] %}
<p>{% trans %}Are you sure you want to send this weekmail?{% endtrans %}</p> <p>{% trans %}Are you sure you want to send this weekmail?{% endtrans %}</p>
{% if request.LANGUAGE_CODE != settings.LANGUAGE_CODE[:2] %} {% 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> <p><strong>{% trans %}Warning: you are sending the weekmail in another language than the default one!{% endtrans %}</strong></p>
{% endif %} {% endif %}
<form method="post" action=""> <form method="post" action="">
{% csrf_token %} {% csrf_token %}
<button type="submit" name="send" value="validate">{% trans %}Send{% endtrans %}</button> <button type="submit" name="send" value="validate">{% trans %}Send{% endtrans %}</button>
</form> </form>
{% endif %} {% endif %}
{% endif %} {% endif %}
<hr> <hr>
{{ weekmail_rendered|safe }} {{ weekmail_rendered|safe }}
{% endblock %} {% endblock %}

View File

@ -1,52 +1,52 @@
<style type="text/css" media="all"> <style type="text/css" media="all">
h1, h2, h3, h4, h5, h6, p { h1, h2, h3, h4, h5, h6, p {
padding: 5px ; padding: 5px ;
margin: 5px; margin: 5px;
} }
img { img {
margin: 5px ; margin: 5px ;
width: 95%; width: 95%;
} }
</style> </style>
<div style="background: #CBD1DD; padding: 0px 5%;"> <div style="background: #CBD1DD; padding: 0px 5%;">
<div style="background: #F9FAFB;"> <div style="background: #F9FAFB;">
<h2 style="background: #000; color: #f9fafb">{{ weekmail.title }}</h2> <h2 style="background: #000; color: #f9fafb">{{ weekmail.title }}</h2>
<img src="{{ weekmail.get_banner() }}" <img src="{{ weekmail.get_banner() }}"
id="OWATemporaryImageDivContainerBannerForOutlook" id="OWATemporaryImageDivContainerBannerForOutlook"
> >
{% if weekmail.intro %} {% if weekmail.intro %}
<h3 style="background: #000; color: #f9fafb">{% trans %}Intro{% endtrans %}</h3> <h3 style="background: #000; color: #f9fafb">{% trans %}Intro{% endtrans %}</h3>
{{ weekmail.intro|markdown }} {{ weekmail.intro|markdown }}
{% endif %} {% endif %}
<h3 style="background: #000; color: #f9fafb">{% trans %}Table of content{% endtrans %}</h3> <h3 style="background: #000; color: #f9fafb">{% trans %}Table of content{% endtrans %}</h3>
<ul> <ul>
{% for a in weekmail.articles.all() %} {% for a in weekmail.articles.all() %}
<li>[{{ a.club }}] {{ a.title }}</li> <li>[{{ a.club }}] {{ a.title }}</li>
{%- endfor %} {%- endfor %}
</ul> </ul>
{%- for a in weekmail.articles.all() %} {%- for a in weekmail.articles.all() %}
<h3 style="background: #000; color: #f9fafb">[{{ a.club }}] {{ a.title }}</h3> <h3 style="background: #000; color: #f9fafb">[{{ a.club }}] {{ a.title }}</h3>
{{ a.content|markdown }} {{ a.content|markdown }}
{%- endfor -%} {%- endfor -%}
{%- if weekmail.joke %} {%- if weekmail.joke %}
<h3 style="background: #000; color: #f9fafb">{% trans %}Joke{% endtrans %}</h3> <h3 style="background: #000; color: #f9fafb">{% trans %}Joke{% endtrans %}</h3>
{{ weekmail.joke|markdown }} {{ weekmail.joke|markdown }}
{% endif -%} {% endif -%}
{%- if weekmail.protip %} {%- if weekmail.protip %}
<h3 style="background: #000; color: #f9fafb">{% trans %}Pro tip{% endtrans %}</h3> <h3 style="background: #000; color: #f9fafb">{% trans %}Pro tip{% endtrans %}</h3>
{{ weekmail.protip|markdown }} {{ weekmail.protip|markdown }}
{% endif -%} {% endif -%}
{%- if weekmail.conclusion %} {%- if weekmail.conclusion %}
<h3 style="background: #000; color: #f9fafb">{% trans %}Final word{% endtrans %}</h3> <h3 style="background: #000; color: #f9fafb">{% trans %}Final word{% endtrans %}</h3>
{{ weekmail.conclusion|markdown }} {{ weekmail.conclusion|markdown }}
{% endif -%} {% endif -%}
<img src="{{ weekmail.get_footer() }}" <img src="{{ weekmail.get_footer() }}"
</div> </div>
</div> </div>

View File

@ -1,8 +1,8 @@
# {{ weekmail.title }} # {{ weekmail.title }}
{%- if weekmail.intro %} {%- if weekmail.intro %}
## {% trans %}Intro{% endtrans %} ## {% trans %}Intro{% endtrans %}
{{ weekmail.intro }} {{ weekmail.intro }}
{% endif %} {% endif %}
## {% trans %}Table of content{% endtrans %} ## {% trans %}Table of content{% endtrans %}
@ -11,22 +11,22 @@
{% endfor -%} {% endfor -%}
{% for a in weekmail.articles.all() %} {% for a in weekmail.articles.all() %}
## [{{ a.club }}] {{ a.title }} ## [{{ a.club }}] {{ a.title }}
{{ a.content }} {{ a.content }}
{% endfor -%} {% endfor -%}
{%- if weekmail.joke %} {%- if weekmail.joke %}
## {% trans %}Joke{% endtrans %} ## {% trans %}Joke{% endtrans %}
{{ weekmail.joke }} {{ weekmail.joke }}
{% endif -%} {% endif -%}
{%- if weekmail.protip %} {%- if weekmail.protip %}
## {% trans %}Pro tip{% endtrans %} ## {% trans %}Pro tip{% endtrans %}
{{ weekmail.protip }} {{ weekmail.protip }}
{% endif -%} {% endif -%}
{%- if weekmail.conclusion %} {%- if weekmail.conclusion %}
## {% trans %}Final word{% endtrans %} ## {% trans %}Final word{% endtrans %}
{{ weekmail.conclusion }} {{ weekmail.conclusion }}
{% endif -%} {% endif -%}

View File

@ -69,11 +69,11 @@ class TestCom(TestCase):
}, },
) )
r = self.client.get(reverse("core:index")) r = self.client.get(reverse("core:index"))
self.assertContains( assert r.status_code == 200
r, self.assertInHTML(
"""<div id="alert_box"> """<div id="alert_box"><div class="markdown"><h3>ALERTE!</h3>
<div class="markdown"><h3>ALERTE!</h3> <p><strong>Caaaataaaapuuuulte!!!!</strong></p>""",
<p><strong>Caaaataaaapuuuulte!!!!</strong></p>""", r.content.decode(),
) )
def test_info_msg(self): def test_info_msg(self):
@ -86,10 +86,12 @@ class TestCom(TestCase):
}, },
) )
r = self.client.get(reverse("core:index")) r = self.client.get(reverse("core:index"))
self.assertContains(
r, assert r.status_code == 200
"""<div id="info_box"> self.assertInHTML(
<div class="markdown"><h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>""", """<div id="info_box"><div class="markdown">
<h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>""",
r.content.decode(),
) )
def test_birthday_non_subscribed_user(self): def test_birthday_non_subscribed_user(self):

View File

@ -50,7 +50,7 @@ from core.views import (
QuickNotifMixin, QuickNotifMixin,
TabedViewMixin, TabedViewMixin,
) )
from core.views.forms import MarkdownInput, TzAwareDateTimeField from core.views.forms import MarkdownInput, SelectDateTime
# Sith object # Sith object
@ -72,12 +72,15 @@ class PosterForm(forms.ModelForm):
widgets = {"screens": forms.CheckboxSelectMultiple} widgets = {"screens": forms.CheckboxSelectMultiple}
help_texts = {"file": _("Format: 16:9 | Resolution: 1920x1080")} help_texts = {"file": _("Format: 16:9 | Resolution: 1920x1080")}
date_begin = TzAwareDateTimeField( date_begin = forms.DateTimeField(
label=_("Start date"), label=_("Start date"),
widget=SelectDateTime,
required=True, required=True,
initial=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), 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): def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None) self.user = kwargs.pop("user", None)
@ -191,9 +194,13 @@ class NewsForm(forms.ModelForm):
"content": MarkdownInput, "content": MarkdownInput,
} }
start_date = TzAwareDateTimeField(label=_("Start date"), required=False) start_date = forms.DateTimeField(
end_date = TzAwareDateTimeField(label=_("End date"), required=False) label=_("Start date"), widget=SelectDateTime, required=False
until = TzAwareDateTimeField(label=_("Until"), 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) automoderation = forms.BooleanField(label=_("Automoderation"), required=False)
@ -258,7 +265,7 @@ class NewsEditView(CanEditMixin, UpdateView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
form = self.get_form() 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) return self.form_valid(form)
else: else:
return self.form_invalid(form) return self.form_invalid(form)

View File

@ -21,8 +21,6 @@
# #
# #
import os
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from core.models import SithFile from core.models import SithFile
@ -37,9 +35,6 @@ class Command(BaseCommand):
) )
def handle(self, *args, **options): 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() files = SithFile.objects.filter(id__in=options["ids"]).all()
for f in files: for f in files:
f._check_fs() f._check_fs()

View File

@ -22,7 +22,7 @@
# #
# #
import os import sys
import sass import sass
from django.conf import settings from django.conf import settings
@ -34,44 +34,36 @@ class Command(BaseCommand):
help = "Compile scss files from static folder" help = "Compile scss files from static folder"
def compile(self, filename): def compile(self, filename: str):
args = {"filename": filename, "include_paths": settings.STATIC_ROOT} args = {
"filename": filename,
"include_paths": settings.STATIC_ROOT.name,
"output_style": "compressed",
}
if settings.SASS_PRECISION: if settings.SASS_PRECISION:
args["precision"] = settings.SASS_PRECISION args["precision"] = settings.SASS_PRECISION
return sass.compile(**args) 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): def handle(self, *args, **options):
if os.path.isdir(settings.STATIC_ROOT): if not settings.STATIC_ROOT.is_dir():
print("---- Compiling scss files ---") raise Exception(
self.exec_on_folder(settings.STATIC_ROOT, self.compilescss) "No static folder availaible, please use collectstatic before compiling scss"
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"
) )
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)
)

View File

@ -21,7 +21,6 @@
# #
# #
from pathlib import Path
from django.conf import settings from django.conf import settings
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
@ -33,7 +32,7 @@ class Command(BaseCommand):
help = "Output the fully rendered SYNTAX.md file" help = "Output the fully rendered SYNTAX.md file"
def handle(self, *args, **options): 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: with open(root_path / "core/fixtures/SYNTAX.md", "r") as md:
result = markdown(md.read()) result = markdown(md.read())
print(result, end="") print(result, end="")

View 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)

View File

@ -21,7 +21,6 @@
# #
# #
import os
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
@ -37,9 +36,6 @@ class Command(BaseCommand):
) )
def handle(self, *args, **options): 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() files = SithFile.objects.filter(id__in=options["ids"]).all()
for f in files: for f in files:
f._repair_fs() f._repair_fs()

View File

@ -13,28 +13,32 @@
# #
# #
import os from django.conf import settings
from django.core.management import call_command from django.core.management import call_command
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
class Command(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): def handle(self, *args, **options):
root_path = os.path.dirname( if not settings.DEBUG:
os.path.dirname(os.path.dirname(os.path.dirname(__file__))) raise Exception("Never call this command in prod. Never.")
) data_dir = settings.BASE_DIR / "data"
try: settings.EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend"
os.mkdir(os.path.join(root_path) + "/data") if not data_dir.is_dir():
print("Data dir created") data_dir.mkdir()
except Exception as e: db_path = settings.BASE_DIR / "db.sqlite3"
repr(e) if db_path.exists():
try: call_command("flush", "--noinput")
os.remove(os.path.join(root_path, "db.sqlite3")) self.stdout.write("Existing database reset")
print("db.sqlite3 deleted")
except Exception as e:
repr(e)
call_command("migrate") call_command("migrate")
self.stdout.write("Add the base fixtures.")
call_command("populate") 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!")

View File

@ -27,6 +27,7 @@ import importlib
import os import os
import unicodedata import unicodedata
from datetime import date, timedelta from datetime import date, timedelta
from pathlib import Path
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from django.conf import settings from django.conf import settings
@ -56,8 +57,6 @@ from django.utils.html import escape
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from phonenumber_field.modelfields import PhoneNumberField from phonenumber_field.modelfields import PhoneNumberField
from core import utils
if TYPE_CHECKING: if TYPE_CHECKING:
from club.models import Club from club.models import Club
@ -377,7 +376,9 @@ class User(AbstractBaseUser):
USERNAME_FIELD = "username" USERNAME_FIELD = "username"
def promo_has_logo(self): 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): def has_module_perms(self, package_name):
return self.is_active return self.is_active

View File

@ -22,7 +22,6 @@
# #
# #
import os
from collections import OrderedDict from collections import OrderedDict
from django.conf import settings from django.conf import settings
@ -37,7 +36,7 @@ class ScssFinder(FileSystemFinder):
def __init__(self, apps=None, *args, **kwargs): def __init__(self, apps=None, *args, **kwargs):
location = settings.STATIC_ROOT location = settings.STATIC_ROOT
if not os.path.isdir(location): if not location.is_dir():
return return
self.locations = [("", location)] self.locations = [("", location)]
self.storages = OrderedDict() self.storages = OrderedDict()

View File

@ -21,61 +21,35 @@
# Place - Suite 330, Boston, MA 02111-1307, USA. # Place - Suite 330, Boston, MA 02111-1307, USA.
# #
# #
import functools
import os from pathlib import Path
from urllib.parse import urljoin
import sass import sass
from django.conf import settings from django.conf import settings
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.templatetags.static import static 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 from core.scss.storage import ScssFileStorage, find_file
class ScssProcessor(object): @functools.cache
"""If DEBUG mode enabled : compile the scss file def _scss_storage():
Else : give the path of the corresponding css supposed to already be compiled return ScssFileStorage()
Don't forget to use compilestatics to compile scss for production.
"""
prefix = iri_to_uri(getattr(settings, "STATIC_URL", "/static/"))
storage = ScssFileStorage()
scss_extensions = [".scss"]
def __init__(self, path=None): def process_scss_path(path: Path):
self.path = path css_path = path.with_suffix(".css")
if settings.DEBUG:
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
compile_args = { compile_args = {
"filename": find_file(self.path), "filename": find_file(path),
"include_paths": settings.SASS_INCLUDE_FOLDERS, "include_paths": settings.SASS_INCLUDE_FOLDERS,
} }
if settings.SASS_PRECISION: if settings.SASS_PRECISION:
compile_args["precision"] = settings.SASS_PRECISION compile_args["precision"] = settings.SASS_PRECISION
content = sass.compile(**compile_args) content = sass.compile(**compile_args)
content = force_bytes(content) storage = _scss_storage()
if storage.exists(css_path):
if self.storage.exists(css_filename): storage.delete(css_path)
self.storage.delete(css_filename) storage.save(css_path, ContentFile(content))
self.storage.save(css_filename, ContentFile(content)) return static(css_path)
return url
def get_converted_scss(self):
if self.path:
return self._convert_scss()
else:
return ""

View File

@ -1,149 +1,149 @@
body{ body{
position: absolute; position: absolute;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
#slideshow{ #slideshow{
position: relative; position: relative;
background-color: lightgrey; 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%; height: 100%;
top: 0;
left: 0;
background: none;
*{ &:before{
-webkit-user-select: none; display: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;
}
} }
#slides{ #slides{
position: relative; height: 100vh;
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;
}
} }
}
#progress_bullets{ #slides{
position: absolute; position: relative;
bottom: 10px; height: 100%;
width: 100%; overflow: hidden;
height: 10px;
display: flex; .slide{
justify-content: center; position: absolute;
width: 100%;
height: 100%;
margin-bottom: 10px; display: inline-flex;
justify-content: center;
.bullet{ top: 0px;
height: 10px;
width: 10px;
margin-left: 5px; background-color: grey;
margin-right: 5px; transition: left 1s ease-out;
border-radius: 50%; img{
max-width: 100%;
background-color: grey; max-height: 100%;
object-fit: contain;
&.active{ }
background-color: #c99836;
}
}
} }
#progress_bar{ .slide.left{
position: absolute; left: -100%;
bottom: 0px;
height: 10px;
background-color: #304c83;
&.init{
width: 0px;
transition: none;
}
&.progress{
width: 100%;
transition: width 10s linear;
}
} }
.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;
}
}
} }

View 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

View 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

File diff suppressed because one or more lines are too long

View 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.

View File

@ -0,0 +1 @@
export*from"./src/es6.js";

View 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};

View File

@ -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};

View File

@ -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};

View File

@ -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};

View File

@ -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;

View File

@ -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)}

View File

@ -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));

View File

@ -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))}}

View File

@ -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,""))}}));

View File

@ -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)};

View File

@ -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;

View File

@ -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);

View File

@ -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)));

View File

@ -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;

View File

@ -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};

View File

@ -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;

View File

@ -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};

View File

@ -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};

View File

@ -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};

View File

@ -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))))}

View 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}))}));

View File

@ -21,9 +21,9 @@
overflow: auto; overflow: auto;
max-width: 100%; max-width: 100%;
font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console",
"Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono",
"Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier,
monospace; monospace;
font-size: 14px; font-size: 14px;
tab-size: 4; tab-size: 4;
border-radius: 4px; border-radius: 4px;

View File

@ -1,5 +1,7 @@
@import "colors";
nav.navbar { nav.navbar {
background-color: hsl(203, 75%, 40%); background-color: $primary-dark-color;
margin: 1em; margin: 1em;
color: white; color: white;
border-radius: 0.6em; border-radius: 0.6em;
@ -43,7 +45,7 @@ nav.navbar {
justify-content: center; justify-content: center;
display: flex !important; display: flex !important;
} }
> .menu, > .menu,
> .link { > .link {
box-sizing: border-box; box-sizing: border-box;
@ -146,5 +148,5 @@ nav.navbar {
} }
} }
} }
} }
} }

View 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;
}
}
}
}

View File

@ -1,39 +1,9 @@
$first-color: hsl(220, 100%, 50%); @import "colors";
$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%);
/*--------------------------MEDIA QUERY HELPERS------------------------*/ /*--------------------------MEDIA QUERY HELPERS------------------------*/
$small-devices: 576px; $small-devices: 576px;
$medium-devices: 768px; $medium-devices: 768px;
$large-devices: 992px; $large-devices: 992px;
$extra-large-devices: 1200px;
/*--------------------------------GENERAL------------------------------*/ /*--------------------------------GENERAL------------------------------*/
@ -43,17 +13,6 @@ body {
font-family: sans-serif; 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, a.button,
button, button,
@ -170,7 +129,7 @@ a:not(.button) {
.shadow { .shadow {
box-shadow: rgba(60, 64, 67, 0.3) 0 1px 3px 0, 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 { .w_big {
@ -246,7 +205,7 @@ a:not(.button) {
#page { #page {
width: 90%; width: 90%;
margin: 20px auto 0; margin: 20px auto 0;
/*---------------------------------NAV---------------------------------*/ /*---------------------------------NAV---------------------------------*/
.btn { .btn {
font-size: 15px; font-size: 15px;
@ -278,7 +237,7 @@ a:not(.button) {
} }
} }
/*--------------------------------CONTENT------------------------------*/ /*--------------------------------CONTENT------------------------------*/
#quick_notif { #quick_notif {
width: 100%; width: 100%;
margin: 0 auto; margin: 0 auto;
@ -357,7 +316,7 @@ a:not(.button) {
} }
} }
/*---------------------------------NEWS--------------------------------*/ /*---------------------------------NEWS--------------------------------*/
#news { #news {
display: flex; display: flex;
@ -385,11 +344,11 @@ a:not(.button) {
background: $second-color; background: $second-color;
box-shadow: $shadow-color 1px 1px 1px; box-shadow: $shadow-color 1px 1px 1px;
padding: 0.4em; padding: 0.4em;
margin: 0em 0em 0.5em 0em; margin: 0 0 0.5em 0;
text-transform: uppercase; text-transform: uppercase;
font-size: 1.1em; font-size: 1.1em;
&:not(:first-of-type) { &: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, #agenda,
#birthdays { #birthdays {
display: block; display: block;
@ -410,7 +369,7 @@ a:not(.button) {
margin-bottom: 1em; margin-bottom: 1em;
#agenda_title, #agenda_title,
#birthdays_title { #birthdays_title {
margin: 0em; margin: 0;
border-radius: 5px 5px 0 0; border-radius: 5px 5px 0 0;
box-shadow: $shadow-color 1px 1px 1px; box-shadow: $shadow-color 1px 1px 1px;
padding: 0.5em; padding: 0.5em;
@ -444,7 +403,7 @@ a:not(.button) {
} }
} }
ul.birthdays_year { ul.birthdays_year {
margin: 0em; margin: 0;
list-style-type: none; list-style-type: none;
font-weight: bold; font-weight: bold;
> li { > li {
@ -454,7 +413,7 @@ a:not(.button) {
} }
} }
ul { ul {
margin: 0em; margin: 0;
margin-left: 1em; margin-left: 1em;
list-style-type: square; list-style-type: square;
list-style-position: inside; 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 { .news_events_group {
box-shadow: $shadow-color 1px 1px 1px; box-shadow: $shadow-color 1px 1px 1px;
margin-left: 1em; margin-left: 1em;
@ -516,14 +475,14 @@ a:not(.button) {
float: left; float: left;
min-width: 7em; min-width: 7em;
max-width: 9em; max-width: 9em;
margin: 0em; margin: 0;
margin-right: 1em; margin-right: 1em;
margin-top: 0.8em; margin-top: 0.8em;
img { img {
max-height: 6em; max-height: 6em;
max-width: 8em; max-width: 8em;
display: block; display: block;
margin: 0em auto; margin: 0 auto;
} }
} }
.news_date { .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 { .news_coming_soon {
display: list-item; display: list-item;
list-style-type: square; list-style-type: square;
list-style-position: inside; list-style-position: inside;
margin-left: 1em; margin-left: 1em;
padding-left: 0em; padding-left: 0;
a { a {
font-weight: bold; font-weight: bold;
text-transform: uppercase; text-transform: uppercase;
@ -561,35 +520,35 @@ a:not(.button) {
font-size: 0.9em; font-size: 0.9em;
} }
} }
/* END COMING SOON */ /* END COMING SOON */
/* NOTICES */ /* NOTICES */
.news_notice { .news_notice {
margin: 0em 0em 1em 1em; margin: 0 0 1em 1em;
padding: 0.4em; padding: 0.4em;
padding-left: 1em; padding-left: 1em;
background: $secondary-neutral-light-color; background: $secondary-neutral-light-color;
box-shadow: $shadow-color 0 0 2px; box-shadow: $shadow-color 0 0 2px;
border-radius: 18px 5px 18px 5px; border-radius: 18px 5px 18px 5px;
h4 { h4 {
margin: 0em; margin: 0;
} }
.news_content { .news_content {
margin-left: 1em; margin-left: 1em;
} }
} }
/* END NOTICES */ /* END NOTICES */
/* CALLS */ /* CALLS */
.news_call { .news_call {
margin: 0em 0em 1em 1em; margin: 0 0 1em 1em;
padding: 0.4em; padding: 0.4em;
padding-left: 1em; padding-left: 1em;
background: $secondary-neutral-light-color; background: $secondary-neutral-light-color;
border: 1px solid grey; border: 1px solid grey;
box-shadow: $shadow-color 1px 1px 1px; box-shadow: $shadow-color 1px 1px 1px;
h4 { h4 {
margin: 0em; margin: 0;
} }
.news_date { .news_date {
font-size: 0.9em; font-size: 0.9em;
@ -598,7 +557,7 @@ a:not(.button) {
margin-left: 1em; margin-left: 1em;
} }
} }
/* END CALLS */ /* END CALLS */
.news_empty { .news_empty {
margin-left: 1em; margin-left: 1em;
@ -631,12 +590,12 @@ a:not(.button) {
width: 19%; width: 19%;
float: left; float: left;
min-width: 15em; min-width: 15em;
margin: 0em; margin: 0;
img { img {
max-height: 15em; max-height: 15em;
max-width: 12em; max-width: 12em;
display: block; display: block;
margin: 0em auto; margin: 0 auto;
margin-bottom: 10px; margin-bottom: 10px;
} }
} }
@ -646,7 +605,6 @@ a:not(.button) {
padding: 0.5em 1em; padding: 0.5em 1em;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
display: inline-block;
font-size: 1.2em; font-size: 1.2em;
border-radius: 2px; border-radius: 2px;
float: right; float: right;
@ -978,7 +936,7 @@ table {
-moz-border-radius: 5px; -moz-border-radius: 5px;
overflow: hidden; overflow: hidden;
box-shadow: rgba(60, 64, 67, 0.3) 0 1px 3px 0, 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) { @media screen and (max-width: 500px) {
@ -1198,8 +1156,8 @@ u,
color: $primary-neutral-dark-color; color: $primary-neutral-dark-color;
height: 100%; height: 100%;
width: 100%; width: 100%;
margin: 0em; margin: 0;
padding: 0em; padding: 0;
display: block; display: block;
} }
} }
@ -1393,7 +1351,7 @@ footer {
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
div { div {
margin: 0.6em 0em; margin: 0.6em 0;
color: $white-color; color: $white-color;
border-radius: 5px; border-radius: 5px;
display: flex; 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;
}
}
}
}
}
}
}

View File

@ -5,287 +5,287 @@ $border: .01rem solid black;
$min_col_width: 100px; $min_col_width: 100px;
.error { .error {
color: red !important; color: red !important;
} }
.radio-btn { .radio-btn {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: $gap; gap: $gap;
> input, > input,
> label { > label {
margin: 0; margin: 0;
} }
&:hover { &:hover {
cursor: pointer; cursor: pointer;
} }
} }
.election_vote { .election_vote {
overflow-x: scroll !important; overflow-x: scroll !important;
} }
.election_table { .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; display: flex;
flex-direction: row; 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 { >.role_text {
display: flex; >h4 {
flex-direction: column-reverse; margin: 0;
align-items: center; }
justify-content: center; >p {
padding: $padding; margin-top: .5em;
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 { >.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; 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; display: flex;
flex-direction: row; flex-direction: column;
background-color: lightgrey; align-items: center;
list-style-type: none;
width: 100%;
gap: $gap;
&:hover { >input[type="radio"]:checked + label,
background-color: lightgrey; >input[type="checkbox"]:checked + label {
} background-color: lightgray;
border-radius: 10px;
>.role_title { >figure>.edit_btns>a:hover{
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;
background-color: #fff; 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 { .election_details {
margin: .5em 0; margin: .5em 0;
} }
.buttons { .buttons {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: $gap; gap: $gap;
} }
.button { .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; color: black;
text-decoration: none; background: #d4d4d4;
background-color: #f2f2f2; }
padding: 0.4em;
margin: 0.1em;
font-size: 1.18em;
border-radius: 5px;
box-shadow: #dfdfdf 0px 0px 1px;
cursor: pointer;
&_send {
background-color: #59aee2;
&:hover { &:hover {
color: black; background-color: rgb(130, 186, 235);
background: #d4d4d4;
}
&_send {
background-color: #59aee2;
&:hover {
background-color: rgb(130, 186, 235);
}
} }
}
} }

View File

@ -199,12 +199,6 @@
> form { > form {
> p { > p {
box-sizing: border-box; box-sizing: border-box;
> input {
width: 100%;
max-width: 100%;
box-sizing: border-box;
}
} }
> .results_on_deck > div { > .results_on_deck > div {
@ -219,12 +213,15 @@
right: 0; right: 0;
} }
} }
input {
> input { min-width: 100%;
width: 100%;
max-width: 100%; max-width: 100%;
box-sizing: border-box; box-sizing: border-box;
} }
button {
font-weight: bold;
}
} }
} }
} }

View File

@ -32,7 +32,6 @@
width: 100%; width: 100%;
} }
// Django moment
> div.mini_profile_link { > div.mini_profile_link {
position: relative; position: relative;
@ -50,7 +49,7 @@
align-items: flex-start; align-items: flex-start;
max-height: 65px; max-height: 65px;
} }
> span { > span {
height: 150px; height: 150px;
width: 100%; width: 100%;
@ -66,14 +65,14 @@
max-height: 100%; max-height: 100%;
height: auto; height: auto;
object-fit: contain; object-fit: contain;
@media (max-width: 375px) { @media (max-width: 375px) {
max-width: 100%; max-width: 100%;
max-height: 65px; max-height: 65px;
} }
} }
} }
> em { > em {
box-sizing: border-box; box-sizing: border-box;
padding: 0 5px; padding: 0 5px;
@ -106,7 +105,6 @@
} }
} }
// Django moment
> a.mini_profile_link { > a.mini_profile_link {
display: none; display: none;
} }

View File

@ -35,7 +35,7 @@ main {
> span { > span {
margin-top: 5px; margin-top: 5px;
} }
> span > span, > span > span,
> span { > span {
display: flex; display: flex;
@ -43,7 +43,7 @@ main {
flex-wrap: wrap; flex-wrap: wrap;
gap: 5px; gap: 5px;
width: 100%; width: 100%;
>.button { >.button {
font-size: smaller; font-size: smaller;
width: 100%; width: 100%;

View File

@ -2,9 +2,9 @@
{% block content %} {% block content %}
<h3>{% trans %}403, Forbidden{% endtrans %}</h3> <h3>{% trans %}403, Forbidden{% endtrans %}</h3>
{{ super() }} {{ super() }}
{% endblock %} {% endblock %}

View File

@ -2,9 +2,9 @@
{% block content %} {% block content %}
<div id="page"> <div id="page">
<h3>{% trans %}404, Not Found{% endtrans %}</h3> <h3>{% trans %}404, Not Found{% endtrans %}</h3>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,27 +1,27 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block head %} {% block head %}
{{ super() }} {{ super() }}
<script <script
src="https://browser.sentry-cdn.com/7.11.1/bundle.min.js" src="https://browser.sentry-cdn.com/7.11.1/bundle.min.js"
integrity="sha384-qcYSo5+/E8hEkPmHFa79GRDsGT84SRhBJHRw3+dbQyh0UwueiFP1jCsRBClEREcs" integrity="sha384-qcYSo5+/E8hEkPmHFa79GRDsGT84SRhBJHRw3+dbQyh0UwueiFP1jCsRBClEREcs"
crossorigin="anonymous" crossorigin="anonymous"
></script> ></script>
{% endblock head %} {% endblock head %}
{% block content %} {% block content %}
<h3>{% trans %}500, Server Error{% endtrans %}</h3> <h3>{% trans %}500, Server Error{% endtrans %}</h3>
{% if settings.SENTRY_DSN %} {% if settings.SENTRY_DSN %}
<script> <script>
Sentry.init({ dsn: '{{ settings.SENTRY_DSN }}' }); Sentry.init({ dsn: '{{ settings.SENTRY_DSN }}' });
Sentry.showReportDialog({ Sentry.showReportDialog({
eventId: '{{ request.sentry_last_event_id() }}', eventId: '{{ request.sentry_last_event_id() }}',
{% if user.is_authenticated %} {% if user.is_authenticated %}
user: { user: {
'name': '{{user.first_name}} {{user.last_name}}', 'name': '{{user.first_name}} {{user.last_name}}',
'email': '{{user.email}}' 'email': '{{user.email}}'
} }
{% endif %} {% endif %}
}) })
</script> </script>
{% endif %} {% endif %}
{% endblock content %} {% endblock content %}

View File

@ -1,342 +1,321 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="fr"> <html lang="fr">
<head> <head>
{% block head %} {% block head %}
<title>{% block title %}{% trans %}Welcome!{% endtrans %}{% endblock %} - Association des Étudiants UTBM</title> <title>{% block title %}{% trans %}Welcome!{% endtrans %}{% endblock %} - Association des Étudiants UTBM</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="{{ static('core/img/favicon.ico') }}"> <link rel="shortcut icon" href="{{ static('core/img/favicon.ico') }}">
<link rel="stylesheet" href="{{ static('core/base.css') }}"> <link rel="stylesheet" href="{{ static('core/base.css') }}">
<link rel="stylesheet" href="{{ static('core/jquery.datetimepicker.min.css') }}"> <link rel="stylesheet" href="{{ static('ajax_select/css/ajax_select.css') }}">
<link rel="stylesheet" href="{{ static('ajax_select/css/ajax_select.css') }}"> <link rel="stylesheet" href="{{ scss('core/style.scss') }}">
<link rel="stylesheet" href="{{ scss('core/style.scss') }}"> <link rel="stylesheet" href="{{ scss('core/markdown.scss') }}">
<link rel="stylesheet" href="{{ scss('core/markdown.scss') }}"> <link rel="stylesheet" href="{{ scss('core/header.scss') }}">
<link rel="stylesheet" href="{{ scss('core/header.scss') }}"> <link rel="stylesheet" href="{{ scss('core/navbar.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 #} {# 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') }}"> <link rel="stylesheet" href="{{ static('core/js/ui/jquery-ui.min.css') }}">
{% endblock %} {% endblock %}
<link rel="preload" as="style" href="{{ static('core/font-awesome/css/font-awesome.min.css') }}" onload="this.onload=null;this.rel='stylesheet'"> <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> <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> <script defer href="{{ static('core/font-awesome/js/fontawesone.min.js') }}"></script>
<!-- Jquery declared here to be accessible in every django widgets --> <!-- 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 --> <!-- 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_css %}{% endblock %}
{% block additional_js %}{% endblock %} {% block additional_js %}{% endblock %}
{% endblock %} {% endblock %}
</head> </head>
<body> <body>
<!-- The token is always passed here to be accessible from the dom --> <!-- 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 --> <!-- 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 --> <!-- BEGIN HEADER -->
{% block header %} {% block header %}
{% if not popup %} {% if not popup %}
<header class="header"> <header class="header">
<div class="header-logo"> <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 class="header-logo-picture" href="{{ url('core:index') }}" style="background-image: url('{{ static('core/img/logo_no_text.png') }}')">
&nbsp; &nbsp;
</a> </a>
<a class="header-logo-text" href="{{ url('core:index') }}"> <a class="header-logo-text" href="{{ url('core:index') }}">
<span>Association des Étudiants</span> <span>Association des Étudiants</span>
<span>de l'Université de Technologie de Belfort-Montbéliard</span> <span>de l'Université de Technologie de Belfort-Montbéliard</span>
</a> </a>
</div> </div>
{% if not user.is_authenticated %} {% if not user.is_authenticated %}
<div class="header-disconnected"> <div class="header-disconnected">
<a class="button" href="{{ url('core:login') }}">{% trans %}Login{% endtrans %}</a> <a class="button" href="{{ url('core:login') }}">{% trans %}Login{% endtrans %}</a>
<a class="button" href="{{ url('core:register') }}">{% trans %}Register{% endtrans %}</a> <a class="button" href="{{ url('core:register') }}">{% trans %}Register{% endtrans %}</a>
</div> </div>
{% else %} {% else %}
<div class="header-connected"> <div class="header-connected">
<div class="left"> <div class="left">
<form class="search" action="{{ url('core:search') }}" method="GET" id="header_search"> <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 class="header-input" type="text" placeholder="{% trans %}Search{% endtrans %}" name="query" id="search" />
<input type="submit" value="{% trans %}Search{% endtrans %}" style="display: none;" /> <input type="submit" value="{% trans %}Search{% endtrans %}" style="display: none;" />
</form> </form>
<ul class="bars"> <ul class="bars">
{% cache 100 "counters_activity" %} {% cache 100 "counters_activity" %}
{% for bar in Counter.objects.annotate_has_barman(user).filter(type="BAR") %} {% for bar in Counter.objects.annotate_has_barman(user).filter(type="BAR") %}
<li> <li>
{# If the user is a barman, we redirect him directly to the barman page {# If the user is a barman, we redirect him directly to the barman page
else we redirect him to the activity page #} else we redirect him to the activity page #}
{% if bar.has_annotated_barman %} {% if bar.has_annotated_barman %}
<a href="{{ url('counter:details', counter_id=bar.id) }}"> <a href="{{ url('counter:details', counter_id=bar.id) }}">
{% else %} {% else %}
<a href="{{ url('counter:activity', counter_id=bar.id) }}"> <a href="{{ url('counter:activity', counter_id=bar.id) }}">
{% endif %} {% endif %}
{% if bar.is_inactive() %} {% if bar.is_inactive() %}
<i class="fa fa-question" style="color: #f39c12"></i> <i class="fa fa-question" style="color: #f39c12"></i>
{% elif bar.is_open %} {% elif bar.is_open %}
<i class="fa fa-check" style="color: #2ecc71"></i> <i class="fa fa-check" style="color: #2ecc71"></i>
{% else %} {% else %}
<i class="fa fa-times" style="color: #eb2f06"></i> <i class="fa fa-times" style="color: #eb2f06"></i>
{% endif %} {% endif %}
<span>{{ bar }}</span> <span>{{ bar }}</span>
</a> </a>
</li> </li>
{% endfor %} {% endfor %}
{% endcache %} {% endcache %}
</ul> </ul>
</div> </div>
<div class="right"> <div class="right">
<div class="user"> <div class="user">
<div class="options"> <div class="options">
<div class="username"> <div class="username">
<a href="{{ url('core:user_profile', user_id=user.id) }}">{{ user.get_display_name() }}</a> <a href="{{ url('core:user_profile', user_id=user.id) }}">{{ user.get_display_name() }}</a>
</div> </div>
<div class="links"> <div class="links">
<a href="{{ url('core:user_tools') }}">{% trans %}Tools{% endtrans %}</a> <a href="{{ url('core:user_tools') }}">{% trans %}Tools{% endtrans %}</a>
<a href="{{ url('core:logout') }}">{% trans %}Logout{% endtrans %}</a> <a href="{{ url('core:logout') }}">{% trans %}Logout{% endtrans %}</a>
</div> </div>
</div> </div>
<a <a
href="{{ url('core:user_profile', user_id=user.id) }}" href="{{ url('core:user_profile', user_id=user.id) }}"
{% if user.profile_pict %} {% if user.profile_pict %}
style="background-image: url('{{ user.profile_pict.get_download_url() }}')" style="background-image: url('{{ user.profile_pict.get_download_url() }}')"
{% else %} {% else %}
style="background-image: url('{{ static('core/img/unknown.jpg') }}')" 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 %}
&nbsp;
{% endif %}
</span>
{% endif %}
</a>
<div id="header_notif">
<ul>
{% if user.notifications.filter(viewed=False).count() > 0 %}
{% for n in user.notifications.filter(viewed=False).order_by('-date') %}
<li>
<a href="{{ url("core:notification", notif_id=n.id) }}">
<div class="datetime">
<span class="header_notif_date">
{{ n.date|localtime|date(DATE_FORMAT) }}
</span>
<span class="header_notif_time">
{{ n.date|localtime|time(DATETIME_FORMAT) }}
</span>
</div>
<div class="reason">
{{ n }}
</div>
</a>
</li>
{% endfor %}
{% else %}
<li class="empty-notification">{% trans %}You do not have any unread notification{% endtrans %}</li>
{% endif %}
</ul>
<div class="options">
<a href="{{ url('core:notification_list') }}">
{% trans %}View more{% endtrans %}
</a>
<a href="{{ url('core:notification_list') }}?see_all">
{% trans %}Mark all as read{% endtrans %}
</a>
</div>
</div>
</div>
</div>
</div>
{% endif %} {% endif %}
<div class="header-lang"> ></a>
{% for language in LANGUAGES %} </div>
<form action="{{ url('set_language') }}" method="post"> <div class="notification">
{% csrf_token %} <a href="#" onclick="display_notif()">
<input name="next" value="{{ request.path }}" type="hidden" /> <i class="fa fa-bell-o"></i>
<input name="language" value="{{ language[0] }}" type="hidden" /> {% set notification_count = user.notifications.filter(viewed=False).count() %}
<input type="submit" value="{% if language[0] == 'en' %}🇬🇧{% else %}🇫🇷{% endif %}" />
</form> {% if notification_count > 0 %}
<span>
{% if notification_count < 100 %}
{{ notification_count }}
{% else %}
&nbsp;
{% endif %}
</span>
{% endif %}
</a>
<div id="header_notif">
<ul>
{% if user.notifications.filter(viewed=False).count() > 0 %}
{% for n in user.notifications.filter(viewed=False).order_by('-date') %}
<li>
<a href="{{ url("core:notification", notif_id=n.id) }}">
<div class="datetime">
<span class="header_notif_date">
{{ n.date|localtime|date(DATE_FORMAT) }}
</span>
<span class="header_notif_time">
{{ n.date|localtime|time(DATETIME_FORMAT) }}
</span>
</div>
<div class="reason">
{{ n }}
</div>
</a>
</li>
{% endfor %} {% 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>
</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 %} {% block info_boxes %}
<div id="info_boxes"> <div id="info_boxes">
{% set sith = get_sith() %} {% set sith = get_sith() %}
{% if sith.alert_msg %} {% if sith.alert_msg %}
<div id="alert_box"> <div id="alert_box">
{{ sith.alert_msg|markdown }} {{ sith.alert_msg|markdown }}
</div> </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 %} {% endif %}
{% if sith.info_msg %}
<div id="info_box">
{{ sith.info_msg|markdown }}
</div>
{% endif %}
</div>
{% endblock %} {% endblock %}
{% else %}
<div id="popupheader">{{ user.get_display_name() }}</div>
{% endif %}
{% endblock %}
<!-- END HEADER --> <!-- END HEADER -->
{% block nav %} {% block nav %}
{% if not popup %} {% if not popup %}
<nav class="navbar"> <nav class="navbar">
<button class="expand-button" onclick="showMenu()"><i class="fa fa-bars"></i></button> <button class="expand-button" onclick="showMenu()"><i class="fa fa-bars"></i></button>
<div id="navbar-content" class="content" style="display: none;"> <div id="navbar-content" class="content" style="display: none;">
<a class="link" href="{{ url('core:index') }}">{% trans %}Main{% endtrans %}</a> <a class="link" href="{{ url('core:index') }}">{% trans %}Main{% endtrans %}</a>
<div class="menu"> <div class="menu">
<span class="head">{% trans %}Associations & Clubs{% endtrans %}</span> <span class="head">{% trans %}Associations & Clubs{% endtrans %}</span>
<ul class="content"> <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='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='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> <li><a href="{{ url('core:page', page_name='utbm-associations') }}">{% trans %}Others UTBM's Associations{% endtrans %}</a></li>
</ul> </ul>
</div> </div>
<div class="menu"> <div class="menu">
<span class="head">{% trans %}Events{% endtrans %}</span> <span class="head">{% trans %}Events{% endtrans %}</span>
<ul class="content"> <ul class="content">
<li><a href="{{ url('election:list') }}">{% trans %}Elections{% endtrans %}</a></li> <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> <li><a href="{{ url('core:page', page_name='ga') }}">{% trans %}Big event{% endtrans %}</a></li>
</ul> </ul>
</div> </div>
<a class="link" href="{{ url('forum:main') }}">{% trans %}Forum{% endtrans %}</a> <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('sas:main') }}">{% trans %}Gallery{% endtrans %}</a>
<a class="link" href="{{ url('eboutic:main') }}">{% trans %}Eboutic{% endtrans %}</a> <a class="link" href="{{ url('eboutic:main') }}">{% trans %}Eboutic{% endtrans %}</a>
<div class="menu"> <div class="menu">
<span class="head">{% trans %}Services{% endtrans %}</span> <span class="head">{% trans %}Services{% endtrans %}</span>
<ul class="content"> <ul class="content">
<li><a href="{{ url('matmat:search_clear') }}">{% trans %}Matmatronch{% endtrans %}</a></li> <li><a href="{{ url('matmat:search_clear') }}">{% trans %}Matmatronch{% endtrans %}</a></li>
<li><a href="/launderette">{% trans %}Launderette{% 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('core:file_list') }}">{% trans %}Files{% endtrans %}</a></li>
<li><a href="{{ url('pedagogy:guide') }}">{% trans %}Pedagogy{% endtrans %}</a></li> <li><a href="{{ url('pedagogy:guide') }}">{% trans %}Pedagogy{% endtrans %}</a></li>
</ul> </ul>
</div> </div>
<div class="menu"> <div class="menu">
<span class="head">{% trans %}My Benefits{% endtrans %}</span> <span class="head">{% trans %}My Benefits{% endtrans %}</span>
<ul class="content"> <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='partenaires')}}">{% trans %}Sponsors{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='avantages') }}">{% trans %}Subscriber benefits{% endtrans %}</a></li> <li><a href="{{ url('core:page', page_name='avantages') }}">{% trans %}Subscriber benefits{% endtrans %}</a></li>
</ul> </ul>
</div> </div>
<div class="menu"> <div class="menu">
<span class="head">{% trans %}Help{% endtrans %}</span> <span class="head">{% trans %}Help{% endtrans %}</span>
<ul class="content"> <ul class="content">
<li><a href="{{ url('core:page', page_name='FAQ') }}">{% trans %}FAQ{% endtrans %}</a></li> <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', 'contacts') }}">{% trans %}Contacts{% endtrans %}</a></li>
<li><a href="{{ url('core:page', page_name='Index') }}">{% trans %}Wiki{% endtrans %}</a></li> <li><a href="{{ url('core:page', page_name='Index') }}">{% trans %}Wiki{% endtrans %}</a></li>
</ul> </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>
</div> </div>
{% endif %}
{% if error %}
{{ error }}
{% endif %}
{% block content %}
{% endblock %}
</div> </div>
</div> </nav>
{% endif %}
{% endblock %}
{% if not popup %} <div id="page">
<footer>
{% block footer %} <ul id="quick_notif">
<div> {% for n in quick_notifs %}
<a href="{{ url('core:page', 'contacts') }}">{% trans %}Contacts{% endtrans %}</a> <li>{{ n }}</li>
<a href="{{ url('core:page', 'legals') }}">{% trans %}Legal notices{% endtrans %}</a> {% endfor %}
<a href="{{ url('core:page', 'copyright_agent') }}">{% trans %}Intellectual property{% endtrans %}</a> </ul>
<a href="{{ url('core:page', 'docs') }}">{% trans %}Help & Documentation{% endtrans %}</a>
<a href="{{ url('core:page', 'rd') }}">{% trans %}R&D{% endtrans %}</a> <div id="content">
</div> {% if list_of_tabs %}
<a href="https://discord.gg/XK9WfPsUFm" target="_link"> <div class="tool_bar">
{% trans %}Site created by the IT Department of the AE{% endtrans %} <div class="tools">
</a> {% for t in list_of_tabs -%}
{% endblock %} <a href="{{ t.url }}" {%- if current_tab==t.slug %} class="selected_tab" {%- endif -%}>{{ t.name }}</a>
<br> {%- endfor %}
<code class="version"> </div>
{% cache 1000 "sith_version" %} </div>
{% trans %}Sith version:{% endtrans %}&nbsp;{{ get_sith().version }}
{% endcache %}
</code>
</footer>
{% endif %} {% 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 %} {% 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 %}&nbsp;{{ 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> </html>

View File

@ -1,16 +1,16 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% 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 %} {% endblock %}
{% block content %} {% block content %}
<h2>{% trans name=form.instance.__class__._meta.verbose_name %}Create {{ name }}{% endtrans %}</h2> <h2>{% trans name=form.instance.__class__._meta.verbose_name %}Create {{ name }}{% endtrans %}</h2>
<form action="" method="post" enctype="multipart/form-data"> <form action="" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{ form.as_p() }} {{ form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -1,7 +1,7 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% trans %}Delete confirmation{% endtrans %} {% trans %}Delete confirmation{% endtrans %}
{% endblock %} {% endblock %}
{% block info_boxes %} {% block info_boxes %}
@ -11,14 +11,14 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<h2>{% trans %}Delete confirmation{% endtrans %}</h2> <h2>{% trans %}Delete confirmation{% endtrans %}</h2>
<form action="" method="post">{% csrf_token %} <form action="" method="post">{% csrf_token %}
<p>{% trans obj=object %}Are you sure you want to delete "{{ obj }}"?{% endtrans %}</p> <p>{% trans obj=object %}Are you sure you want to delete "{{ obj }}"?{% endtrans %}</p>
<input type="submit" value="{% trans %}Confirm{% endtrans %}" /> <input type="submit" value="{% trans %}Confirm{% endtrans %}" />
</form> </form>
<form method="GET" action="javascript:history.back();"> <form method="GET" action="javascript:history.back();">
<input type="submit" name="cancel" value="{% trans %}Cancel{% endtrans %}" /> <input type="submit" name="cancel" value="{% trans %}Cancel{% endtrans %}" />
</form> </form>
{% endblock %} {% endblock %}

View File

@ -1,24 +1,24 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% if object %} {% if object %}
{% trans obj=object %}Edit {{ obj }}{% endtrans %} {% trans obj=object %}Edit {{ obj }}{% endtrans %}
{% else %} {% else %}
{% trans %}Save{% endtrans %} {% trans %}Save{% endtrans %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% if object %} {% if object %}
<h2>{% trans obj=object %}Edit {{ obj }}{% endtrans %}</h2> <h2>{% trans obj=object %}Edit {{ obj }}{% endtrans %}</h2>
{% else %} {% else %}
<h2>{% trans %}Save{% endtrans %}</h2> <h2>{% trans %}Save{% endtrans %}</h2>
{% endif %} {% endif %}
<form action="" method="post" enctype="multipart/form-data"> <form action="" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{ form.as_p() }} {{ form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -1,62 +1,62 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %} {% block title %}
{% if file %} {% if file %}
{{ file.get_display_name() }} {{ file.get_display_name() }}
{% elif file_list %} {% elif file_list %}
{% trans %}File list{% endtrans %} {% trans %}File list{% endtrans %}
{% elif new_file %} {% elif new_file %}
{% trans %}New file{% endtrans %} {% trans %}New file{% endtrans %}
{% else %} {% else %}
{% trans %}Not found{% endtrans %} {% trans %}Not found{% endtrans %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% macro print_file_name(file) %} {% macro print_file_name(file) %}
{% if file %} {% if file %}
{{ print_file_name(file.parent) }} > {{ print_file_name(file.parent) }} >
<a href="{{ url('core:file_detail', file_id=file.id, popup=popup) }}">{{ file.get_display_name() }}</a> <a href="{{ url('core:file_detail', file_id=file.id, popup=popup) }}">{{ file.get_display_name() }}</a>
{% else %} {% else %}
<a href="{{ url('core:file_list', popup) }}">{% trans %}Files{% endtrans %}</a> <a href="{{ url('core:file_list', popup) }}">{% trans %}Files{% endtrans %}</a>
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}
{% block content %} {% block content %}
{{ print_file_name(file) }} {{ print_file_name(file) }}
<div class="tool_bar"> <div class="tool_bar">
<div class="tools"> <div class="tools">
<div> <div>
{% set home = user.home %} {% set home = user.home %}
{% if home %} {% if home %}
<a href="{{ url('core:file_detail', home.id, popup) }}">{% trans %}My files{% endtrans %}</a> <a href="{{ url('core:file_detail', home.id, popup) }}">{% trans %}My files{% endtrans %}</a>
{% endif %} {% endif %}
</div> </div>
{% if file %} {% if file %}
<a href="{{ url('core:file_detail', file.id, popup) }}">{% trans %}View{% endtrans %}</a> <a href="{{ url('core:file_detail', file.id, popup) }}">{% trans %}View{% endtrans %}</a>
{% if can_edit(file, user) %} {% 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 %} {% endif %}
{% if can_edit_prop(file, user) %} {% if can_edit_prop(file, user) %}
<a href="{{ url('core:file_prop', file_id=file.id, popup=popup) }}">{% trans %}Prop{% endtrans %}</a> <a href="{{ url('core:file_prop', file_id=file.id, popup=popup) }}">{% trans %}Prop{% endtrans %}</a>
{% endif %}
{% endif %} {% endif %}
{% endif %}
</div> </div>
</div> </div>
<hr> <hr>
{% if file %} {% if file %}
{% block file %} {% block file %}
{% endblock %} {% endblock %}
{% endif %} {% endif %}
{% block script %} {% block script %}
{{ super() }} {{ super() }}
{% if popup %} {% if popup %}
<script> <script>
parent.$(".choose_file_widget").css("height", "75%"); parent.$(".choose_file_widget").css("height", "75%");
</script> </script>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% endblock %} {% endblock %}

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