Commit 8ac47a91 authored by Thom Wiggers's avatar Thom Wiggers 📐
Browse files

Merge branch '1-documents' into 'master'

Create documents application

Closes #1, but #18 remains unresolved. Writing more Python code seems more productive at the moment.

See merge request !8
parents aa63cf13 a4dc34bb
from django.contrib import admin
from documents.models import AssociationDocumentsYear
from documents.models import MiscellaneousDocument
from documents.models import GeneralMeeting, GeneralMeetingDocument
class GeneralMeetingDocInline(admin.StackedInline):
model = GeneralMeetingDocument
@admin.register(GeneralMeeting)
class GeneralMeetingAdmin(admin.ModelAdmin):
inlines = (GeneralMeetingDocInline, )
admin.site.register(MiscellaneousDocument)
admin.site.register(AssociationDocumentsYear)
from django.apps import AppConfig
class DocumentsConfig(AppConfig):
name = 'documents'
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-07-26 20:13+0200\n"
"PO-Revision-Date: 2016-07-26 20:14+0100\n"
"Last-Translator: Joost Rijneveld <joost@joostrijneveld.nl>\n"
"Language-Team: \n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.6.10\n"
#: templates/documents/index.html:5
msgid "Documents"
msgstr "Documenten"
#: templates/documents/index.html:14
msgid "Miscellaneous Documents"
msgstr "Algemeen"
#: templates/documents/index.html:16
msgid ""
"Thalia was officially founded on November 7th, 1990. The relevant statutes "
"and internal rules can be accessed here. The statues have last been amended "
"in September 2007; the internal rules have been changed on several "
"occasions. Other miscellaneous documents can be found here as well, such as "
"the declaration form and the canteen regulations. Please read these "
"carefully, so that we can all have a pleasant time when having drinks in the "
"canteen."
msgstr ""
"7 november 1990 is Thalia officieel opgericht. De bijbehorende statuten en "
"huisregels zijn hier opvraagbaar. De statuten zijn in september 2007 voor "
"het laatst bijgewerkt; de huisregels zijn meerdere keren veranderd. Verder "
"zijn hier diverse andere documenten te vinden, zoals het declaratieformulier "
"en de kantinereglementen. Lees ze door zodat we allemaal op een fijne manier "
"door kunnen borrelen in de kantine."
#: templates/documents/index.html:26
msgid "Policy Documents &amp; Annual Reports"
msgstr "Beleidsdocumenten &amp; Jaarverslagen"
#: templates/documents/index.html:29
msgid ""
"Every candidate board of Thalia drafts a policy document before being "
"installed, to detail their plans for the next year. This also includes a "
"general planning of all activities, as well as the budget for that year. "
"Furthermore, the association is obliged to deliver an annual report and "
"provide a financial overview. These documents show the financial "
"developments over the year, what contacts Thalia maintained and what "
"activities were organized. All historical policy documents and reports are "
"made available, below."
msgstr ""
"Een aankomend bestuur van Thalia stelt voor installatie een beleidsplan op "
"waarin wordt aangegeven wat voor koers het als bestuur wil gaan varen. "
"Daarnaast wordt een globale planning gegeven van alle activiteiten en wordt "
"natuurlijk een jaarbegroting opgesteld. Verder is een studievereniging "
"verplicht een jaarverslag te maken en hierbij onder andere een financieel "
"overzicht te verschaffen. Hierin kan je vinden hoe het jaar financieel "
"verlopen is, welke contacten Thalia heeft onderhouden en welke activiteiten "
"er zijn georganiseerd. In het onderstaande overzicht zijn de afgelopen "
"beleidsplannen en jaarverslagen terug te vinden."
#: templates/documents/index.html:36
msgid "Policy"
msgstr "Beleidsdocument"
#: templates/documents/index.html:41
msgid "Annual report"
msgstr "Jaarverslag"
#: templates/documents/index.html:50
msgid "General Meetings"
msgstr "Algemene Ledenvergaderingen"
#: templates/documents/index.html:53
msgid ""
"The General Meetings (ALVs) can be attended by all members, honorary members "
"and donors. Thalia organizes at least two general meetings each year. "
"Minutes of these meetings are made available below. This allows (honorary) "
"members and donors that did not attend to get an insight in what was "
"discussed as well."
msgstr ""
"De Algemene Ledenvergaderingen (ALVs) kunnen door alle leden, ereleden en "
"begunstigers worden bijgewoond. Binnen Thalia wordt tenminste twee maal per "
"jaar een ALV georganiseerd. Naar aanleiding van deze vergaderingen worden "
"notulen gemaakt die hieronder zijn in te zien. Zo kunnen ook de (ere)leden "
"en begunstigers die niet aanwezig waren teruglezen wat er allemaal besproken "
"is."
#: templates/documents/meetingyear.html:4
msgid "General Meetings of"
msgstr "ALV's van"
#: templates/documents/meetingyear.html:12
msgid "Meeting"
msgstr "ALV"
#: templates/documents/meetingyear.html:39
msgid "No minutes<br>available"
msgstr "Geen notulen<br>beschikbaar"
#: templates/documents/meetingyear.html:44
msgid "Only signed-in users can view<br>General Meeting documents."
msgstr "ALV-stukken zijn alleen in te zien<br>door ingelogde gebruikers."
# -*- coding: utf-8 -*-
# Generated by Django 1.10b1 on 2016-07-14 20:47
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import utils.validators
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='AssociationDocument',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('year', models.IntegerField()),
('file', models.FileField(upload_to='documents/association/', validators=[utils.validators.validate_file_extension])),
('filetype', models.CharField(choices=[('policy-document', 'Policy document'), ('annual-report', 'Annual report'), ('financial-report', 'Financial report')], max_length=16)),
],
),
migrations.CreateModel(
name='GeneralMeeting',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('minutes', models.FileField(upload_to='documents/meetings/minutes/', validators=[utils.validators.validate_file_extension])),
('datetime', models.DateTimeField()),
('location', models.CharField(max_length=200)),
],
),
migrations.CreateModel(
name='GeneralMeetingDocument',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('file', models.FileField(upload_to='documents/meetings/files/', validators=[utils.validators.validate_file_extension])),
('meeting', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='documents.GeneralMeeting')),
],
),
migrations.CreateModel(
name='GenericDocument',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('file', models.FileField(upload_to='documents/generic/', validators=[utils.validators.validate_file_extension])),
('members_only', models.BooleanField(default=False)),
],
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10b1 on 2016-07-23 10:47
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
import utils.validators
class Migration(migrations.Migration):
dependencies = [
('documents', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='AssociationDocumentsYear',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('year', models.IntegerField(unique=True, validators=[django.core.validators.MinValueValidator(1990)])),
('policy_document', models.FileField(blank=True, upload_to='documents/association/', validators=[utils.validators.validate_file_extension])),
('annual_report', models.FileField(blank=True, upload_to='documents/association/', validators=[utils.validators.validate_file_extension])),
('financial_report', models.FileField(blank=True, upload_to='documents/association/', validators=[utils.validators.validate_file_extension])),
],
),
migrations.DeleteModel(
name='AssociationDocument',
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10b1 on 2016-07-24 11:14
from __future__ import unicode_literals
from django.db import migrations, models
import utils.validators
class Migration(migrations.Migration):
dependencies = [
('documents', '0002_auto_20160723_1247'),
]
operations = [
migrations.CreateModel(
name='MiscellaneousDocument',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('file', models.FileField(upload_to='documents/miscellaneous/', validators=[utils.validators.validate_file_extension])),
('members_only', models.BooleanField(default=False)),
],
),
migrations.DeleteModel(
name='GenericDocument',
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10rc1 on 2016-07-25 21:46
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('documents', '0003_auto_20160724_1314'),
]
operations = [
migrations.AlterModelOptions(
name='generalmeeting',
options={'ordering': ['datetime']},
),
]
from django.db import models
from django.core.validators import MinValueValidator
from utils.validators import validate_file_extension
class AssociationDocumentsYear(models.Model):
year = models.IntegerField(
unique=True,
validators=[MinValueValidator(1990)],
)
policy_document = models.FileField(
upload_to='documents/association/',
validators=[validate_file_extension],
blank=True,
)
annual_report = models.FileField(
upload_to='documents/association/',
validators=[validate_file_extension],
blank=True,
)
financial_report = models.FileField(
upload_to='documents/association/',
validators=[validate_file_extension],
blank=True,
)
def __str__(self):
return "{}-{}".format(self.year, self.year + 1)
class MiscellaneousDocument(models.Model):
name = models.CharField(max_length=200)
file = models.FileField(
upload_to='documents/miscellaneous/',
validators=[validate_file_extension],
)
members_only = models.BooleanField(default=False)
def __str__(self):
return self.name
class GeneralMeeting(models.Model):
minutes = models.FileField(
upload_to='documents/meetings/minutes/',
validators=[validate_file_extension],
)
datetime = models.DateTimeField()
location = models.CharField(max_length=200)
class Meta:
ordering = ['datetime']
class GeneralMeetingDocument(models.Model):
meeting = models.ForeignKey(GeneralMeeting, on_delete=models.CASCADE)
file = models.FileField(
upload_to='documents/meetings/files/',
validators=[validate_file_extension],
)
def __str__(self):
return self.file.name
/* https://kenneth.io/blog/2012/03/04/word-wrapping-hypernation-using-css/ */
.wordbreak {
-ms-word-break: break-all;
word-break: break-all;
/* Non standard for webkit */
word-break: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
}
#alvcontainer > div:not(:first-child) {
display: none;
}
\ No newline at end of file
.unknowncontainer .post-header {
text-align:center;
height:176px; /* 176 - padding */
width:220px;
font-size:64px;
line-height: 176px;
cursor:default;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.unknowncontainer {
background:none !important;
border:2px dashed #9C9C9C;
color:#9C9C9C;
}
.policywrapper {
overflow-x:hidden;
padding-top:20px;
}
.slider-control-prev,
.slider-control-next {
cursor:pointer;
}
.slider-control-prev {
display:none;
}
ul {
margin-bottom:0px !important;
}
$(function() {
function select_meeting(year) {
$("#alvcontainer > div").hide();
$("#meeting-"+year).show();
}
$(".meeting-btn").on('click', function(e) {
select_meeting($(this).data('year'));
})
$("#alvselect").on('change', function(e) {
select_meeting($("#alvselect").val());
})
});
$(function() {
function scrollSlider(slider, direction) {
var wrapper = slider.children('.policywrapper');
var delta = direction * (slider.width() + 20); // +20 for margin
if (wrapper.scrollLeft() + delta <= 0) {
slider.children('.slider-control-prev').fadeOut(200);
}
else {
slider.children('.slider-control-prev').fadeIn(200);
}
if (wrapper.scrollLeft() + 2*delta >= wrapper.children('ul').width()) {
slider.children('.slider-control-next').fadeOut(200);
}
else {
slider.children('.slider-control-next').fadeIn(200);
}
wrapper.animate({scrollLeft: wrapper.scrollLeft() + delta});
}
$('.slider-control-next').click(function() {
scrollSlider($(this).parent(), 1);
});
$('.slider-control-prev').click(function() {
scrollSlider($(this).parent(), -1);
});
});
{% extends 'base.html' %}
{% load staticfiles %}
{% load i18n %}
{% block page_title %}{% trans "Documents" %}{% endblock %}
{% block css_head %}
{{ block.super }}
<link href="{% static "documents/css/policydocuments.css" %}" rel="stylesheet" type="text/css">
<link href="{% static "documents/css/generalmeetings.css" %}" rel="stylesheet" type="text/css">
{% endblock %}
{% block body %}
<h1 class="main-title">{% trans "Miscellaneous Documents" %}</h1>
<p class="text-center">{% trans "Thalia was officially founded on November 7th, 1990. The relevant statutes and internal rules can be accessed here. The statues have last been amended in September 2007; the internal rules have been changed on several occasions. Other miscellaneous documents can be found here as well, such as the declaration form and the canteen regulations. Please read these carefully, so that we can all have a pleasant time when having drinks in the canteen." %}</p>
<div class="portfolio">
<ul class="portfolio-posts row" style="padding-top:20px;">
{% for miscellaneous_document in miscellaneous_documents %}
{% include 'documents/miscellaneous.html' with document=miscellaneous_document %}
{% endfor %}
</ul>
</div>
<h1 class="main-title">{% trans "Policy Documents &amp; Annual Reports" %}</h1>
<p class="text-center">
{% trans "Every candidate board of Thalia drafts a policy document before being installed, to detail their plans for the next year. This also includes a general planning of all activities, as well as the budget for that year. Furthermore, the association is obliged to deliver an annual report and provide a financial overview. These documents show the financial developments over the year, what contacts Thalia maintained and what activities were organized. All historical policy documents and reports are made available, below." %}
</p>
<div class='portfolio slider'>
<div class='policywrapper'>
<ul class="portfolio-posts row" style='width:{{ assocation_docs_width }}px'>
{% for year, docs in association_documents_years %}
{% include 'documents/policydocument.html' with documents=docs.policy name=_("Policy") year=year %}
{% endfor %}
</ul>
<ul class="portfolio-posts row" style='width:{{ assocation_docs_width }}px'>
{% for year, docs in association_documents_years %}
{% include 'documents/policydocument.html' with documents=docs.report name=_("Annual report") year=year %}
{% endfor %}
</ul>
</div>
<a class="slider-control-prev"></a>
<a class="slider-control-next"></a>
</div>
<h1 class="main-title">{% trans "General Meetings" %}</h1>
<p class="text-center">
{% trans "The General Meetings (ALVs) can be attended by all members, honorary members and donors. Thalia organizes at least two general meetings each year. Minutes of these meetings are made available below. This allows (honorary) members and donors that did not attend to get an insight in what was discussed as well." %}
</p>
<div class="tcenter" style='margin-bottom:20px;'>
{% for year, meetings in meeting_years|slice:"5" %}
<button class="meeting-btn btn-large btn-style2" data-year="{{ year }}">{{ year }}-{{ year|add:1 }}</button>
{% endfor %}
<select id='alvselect' name='alvselect' class="btn-large btn-style2" style='outline-width:0px !important;width:140px;padding:0px 15px;'>
{% for year, meetings in meeting_years|slice:"5:" %}
<option value='{{ year }}'>{{ year }}-{{ year|add:1 }}</option>
{% endfor %}
</select>
</div>
<div id='alvcontainer'>
{% for year, meetings in meeting_years %}
<div id='meeting-{{ year }}'>
{% include 'documents/meetingyear.html' with meetings=meetings year=year %}
</div>
{% endfor %}
</div>
{% endblock %}
{% block js_body %}
{{ block.super }}
<script type="text/javascript" src="{% static "documents/js/policydocuments.js" %}"></script>
<script type="text/javascript" src="{% static "documents/js/generalmeetings.js" %}"></script>
{% endblock %}
\ No newline at end of file
{% load i18n %}
{% load filename %}
<h2 style="margin-bottom: 0px;">{% trans "General Meetings of" %} {{ year }}-{{ year|add:1 }}:</span></h2>
{% for meeting in meetings %}
<div class="gw-go gw-go-clearfix gw-go-{% if meetings|length < 3 %}3{% else %}{{ meetings | length }}{% endif %}cols">
<div class="gw-go-col-wrap">
<div class="gw-go-col gw-go-style1">
<div class="gw-go-header">
<div class="gw-go-header-top">
<h3>{% trans "Meeting" %} {{ forloop.counter }}</h3><span class="circle-icon-mail"></span>
<div class="gw-go-coin-wrap">
<div class="gw-go-coinf gw-go-coinb">
<div>
{% if meeting.datetime %}
{{ meeting.datetime|date:'j' }}
<small>{{ meeting.datetime|date:'M'|upper }}</small>
{% else %}
?<small>?</small>
{% endif %}
</div>
</div>
</div>
</div>
<div class="gw-go-header-bottom"></div>
<p>{{ meeting.location }}</p>
</div>
{% if user.is_authenticated %}
<ul class="gw-go-body">
{% for document in meeting.generalmeetingdocument_set.all %}
<li class="wordbreak"><a href="{% url 'documents:general-meeting-document' meeting.pk document.pk %}" target="_blank">{{ document|filename }}</a></li>
{% endfor %}
</ul>
<div class="gw-go-footer">
{% if meeting.minutes %}
<a href="{% url 'documents:minutes' meeting.pk %}" class="gw-go-btn gw-go-btn-medium" target="_blank">Notulen</a>
{% else %}
<div style='padding-top:10px;'>{% trans "No minutes<br>available" %}</div>
{% endif %}
</div>
{% else %}
<div class="gw-go-body">
{% trans "Only signed-in users can view<br>General Meeting documents." %}
</div>
<div class="gw-go-footer">
</div>
{% endif %}
</div>
</div>
</div>
{% empty %}
<div style="text-align:center;margin-top:10px;">There are no General Meetings available for {{ year }}-{{ year | add:1 }}</div>
{% endfor %}
\ No newline at end of file
<li class="post span3 has-overlay">
<div class="post-inner">
<div class="post-header">
<a href="portfolio-single-wide.html">
<!-- TODO create a more meaningful thumbnail -->