Unverified Commit e70a2d0d authored by Joost Rijneveld's avatar Joost Rijneveld

Merge branch 'master' into 33-migrate-members

parents f3641fc7 8434dd57
* text=auto eol=lf
# Images should be treated as binary
*.png binary
*.jpeg binary
......
......@@ -14,8 +14,6 @@ pep8:
- pip install tox
script:
- tox -e $PYTHON_VERSION
services:
- mysql:latest
python34:
<<: *djangotest
......
# Dit bestand regelt een mooie weergave in git shortlog.
# Who Other identity
# somehow heeft Sébastiaan er drie nodig om ze samen te voegen
Sébastiaan Versteeg <se_bastiaan@outlook.com> <sebastiaan@jupiter.local>
Sébastiaan Versteeg <se_bastiaan@outlook.com> <s.versteeg@student.science.ru.nl>
Sébastiaan Versteeg <se_bastiaan@outlook.com> <se_bastiaan@outlook.com>
Thom Wiggers <thom@thomwiggers.nl> <t.wiggers@student.science.ru.nl>
Jan Martens <jan-martens@hotmail.com> <jan-martens@hotmail.com>
Luuk Scholten <info@luukscholten.com> <l.scholten@student.science.ru.nl>
Joost Rijneveld <joost@joostrijneveld.nl> <l.rijneveld@science.ru.nl>
Nienke Wessel <n.wessel@xs4all.nl>
This diff is collapsed.
tox
flake8
factory_boy==2.7.0
Faker==0.7.3
git+https://github.com/azaghal/pydenticon
# Data migrations
The old new website of Study Association Thalia contained a lot of data.
Before we can launch the new website, all old data has to be migrated
to the new website.
The migration instructions for each part of the website are shown below.
## Active members
## Documents
## Education
## Events
## Mailing lists
## Members
## Newsletters
## Partners
## Photos
## Pizzas
## Thabloids
## Merchandise
......@@ -105,7 +105,7 @@ class Board(Committee):
)
def get_absolute_url(self):
return reverse('committees:board', args=[str(self.pk)])
return reverse('activemembers:board', args=[str(self.pk)])
class ActiveMembershipManager(models.Manager):
......@@ -212,6 +212,12 @@ class CommitteeMembership(models.Model, metaclass=ModelTranslateMeta):
'member': _('This member is already in the committee for '
'this period')})
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.member.user.is_staff = self.member.membership_set.exclude(
until__lt=timezone.now().date()).count() >= 1
self.member.user.save()
def __str__(self):
return "{} membership of {} since {}, until {}".format(self.member,
self.committee,
......
......@@ -9,7 +9,7 @@ class StaticViewSitemap(sitemaps.Sitemap):
changefreq = 'daily'
def items(self):
return ['activemembers:committees', 'committees:boards']
return ['activemembers:committees', 'activemembers:boards']
def location(self, item):
return reverse(item)
......
{% extends 'base.html' %}
{% load i18n thumbnail static %}
{% block title %}{% trans "Boards" %} — {{ block.super }}{% endblock %}
{% block title %}{% trans "Board" %} {{ board.since.year }}-{{ board.until.year }} — {% trans "Boards" %} — {{ block.super }}{% endblock %}
{% block body %}
<h1>
{% trans "Board" %} {{ board.since.year }}-{{ board.until.year }}
<span class="title-meta clearfix">
<span>
<a class="back" href="{% url 'committees:boards' %}" id="collectionButton"></a>
<a class="back" href="{% url 'activemembers:boards' %}" id="collectionButton"></a>
</span>
</span>
</h1>
......
......@@ -6,7 +6,6 @@
<h1>{% trans 'Boards' %}</h1>
<p style="text-align: center;">
{% url 'committees:board_old' as old_boards_url %}
{% blocktrans trimmed %}
Thalia's board makes sure all operations during the academic year are taken care of, in front or behind the scenes. If you have any questions then you can address them during the day or, if you're not always on the campus, you're always welcome to <a href="mailto:info@thalia.nu">send them an email</a>.
{% endblocktrans %}
......
......@@ -6,7 +6,7 @@
<h1>{{ committee.name }}
<span class="title-meta clearfix">
<span>
<a class="back" href="{% url 'committees:committees' %}" id="collectionButton"></a>
<a class="back" href="{% url 'activemembers:committees' %}" id="collectionButton"></a>
</span>
</span>
</h1>
......
......@@ -7,6 +7,7 @@ from documents.models import GeneralMeeting, GeneralMeetingDocument
class GeneralMeetingDocInline(admin.StackedInline):
model = GeneralMeetingDocument
classes = ('collapse',)
@admin.register(GeneralMeeting)
......
import os
import requests
from bs4 import BeautifulSoup
from django.core.files.base import ContentFile
from documents.models import MiscellaneousDocument
from utils.management.commands import legacylogin
def filefield_from_url(filefield, url):
file = ContentFile(requests.get(url).content)
filefield.save(os.path.basename(url), file)
class Command(legacylogin.Command):
help = "Scrapes the Miscellaneous Documents from the old Thalia website"
def handle(self, *args, **options):
super().handle(*args, **options)
url = "https://thalia.nu/association/documents"
documentpage = self.session.get(url)
soup = BeautifulSoup(documentpage.text, 'lxml')
container = soup(attrs={'class': 'generalcontainer'})[0]
documents = container.find_all('li', recursive=False)
for document in documents:
name = document.find('h2').find(text=True)
obj, cr = MiscellaneousDocument.objects.get_or_create(name=name)
url = document.find(attrs={'class': 'overlay-icon-link'})
if url is not None:
url = "https://thalia.nu" + url['href']
filefield_from_url(obj.file, url)
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-09-07 17:34
from __future__ import unicode_literals
from django.db import migrations, models
import utils.validators
class Migration(migrations.Migration):
dependencies = [
('documents', '0005_auto_20160813_1116'),
]
operations = [
migrations.AlterField(
model_name='generalmeeting',
name='minutes',
field=models.FileField(blank=True, upload_to='documents/meetings/minutes/', validators=[utils.validators.validate_file_extension]),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-09-30 12:47
from __future__ import unicode_literals
from django.db import migrations, models
import utils.validators
class Migration(migrations.Migration):
dependencies = [
('documents', '0006_auto_20160907_1934'),
]
operations = [
migrations.AlterField(
model_name='generalmeeting',
name='minutes',
field=models.FileField(blank=True, null=True, upload_to='documents/meetings/minutes/', validators=[utils.validators.validate_file_extension]),
),
]
......@@ -50,6 +50,8 @@ class GeneralMeeting(models.Model):
minutes = models.FileField(
upload_to='documents/meetings/minutes/',
validators=[validate_file_extension],
blank=True,
null=True,
)
datetime = models.DateTimeField()
location = models.CharField(max_length=200)
......
/* 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;
}
#meetingcontainer > 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;
}
.thimbus-page {
.policy-wrapper {
overflow-x: hidden;
padding-top: 20px;
}
.policy-wrapper, .misc-wrapper {
.portfolio-posts {
margin-bottom: 0;
.slider-control-prev,
.slider-control-next {
cursor: pointer;
}
.slider-control-prev {
display: none;
}
.post {
width: 220px;
float: left;
min-height: 1px;
margin-left: 20px;
.document-thumb {
position: relative;
> span {
width: 100%;
position: absolute;
bottom: 40px;
text-align: center;
font-family: 'GillSansMT-Condensed', 'Open Sans', Helvetica, sans-serif;
font-size: 20px;
}
}
.unknowncontainer {
background: none !important;
border: 2px dashed #9C9C9C;
color: #9C9C9C;
height: 310px;
.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;
}
}
}
}
}
/* 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;
}
#meetingcontainer > div:not(:first-child) {
display: none;
}
#alvselect {
outline-width: 0px !important;
width: 140px;
padding: 0px 15px;
}
}
/* Portrait tablet to landscape and desktop */
@media (min-width: 768px) and (max-width: 979px) {
.thimbus-page {
.policy-wrapper, .misc-wrapper {
width: 700px;
margin: 0 auto;
.portfolio-posts {
.post {
min-width: 220px;
width: 220px;
}
}
}
}
}
/* Landscape phone to portrait tablet */
@media (max-width: 767px) {
.thimbus-page {
.policy-wrapper, .misc-wrapper {
.portfolio-posts {
.post {
min-width: 190px;
width: 190px;
.unknowncontainer {
height: 268px;
.post-header {
width: 190px;
}
}
}
}
}
}
}
\ No newline at end of file
{% load staticfiles %}
{% if documents %}
<li class="post span3 has-overlay">
<li class="post has-overlay">
<div class="post-inner">
<div class="post-header">
<a href="portfolio-single-wide.html">
<!-- TODO create a more meaningful thumbnail -->
<img src="https://placehold.it/200x200" />
</a>
</div>
<div class="post-body">
<h2><a href="portfolio-single-wide.html">{{ name }} {{ year|stringformat:"d"|slice:"2:4" }}-'{{ year | add:1 | stringformat:"d" | slice:"2:4" }}</a></h2>
<div class="document-thumb">
<img src="{% static "documents/images/thumb.png" %}" />
<span>{{ name | upper }} {{ year | stringformat:"d" | slice:"2:4" | upper }}-'{{ year | add:1 | stringformat:"d" | slice:"2:4" | upper }}</span>
</div>
</div>
<div class="post-overlay">
<div class="post-overlay-meta">
......@@ -22,13 +21,13 @@
</div>
</li>
{% else %}
<li class="post span3">
<li class="post">
<div class="post-inner unknowncontainer">
<div class="post-header">
?
</div>
<div class="post-body">
<h2>{{ name }} '{{ year | stringformat:"d" | slice:"2:4" }}-'{{ year | add:1 | stringformat:"d" | slice:"2:4" }}</h2>
<h2>{{ name | upper }} '{{ year | stringformat:"d" | slice:"2:4" | upper }}-'{{ year | add:1 | stringformat:"d" | slice:"2:4" | upper }}</h2>
</div>
</div>
</li>
......
<li class="post span3 has-overlay">
{% load staticfiles %}
<li class="post has-overlay">
<div class="post-inner">
<div class="post-header">
<a href="portfolio-single-wide.html">
<!-- TODO create a more meaningful thumbnail -->
<img src="https://placehold.it/200x200" />
</a>
</div>
<div class="post-body">
<h2><a href="portfolio-single-wide.html">{{ document.name }}</a></h2>
<div class="document-thumb">
<img src="{% static "documents/images/thumb.png" %}" />
<span>{{ document.name | upper }}</span>
</div>
</div>
<div class="post-overlay">
<div class="post-overlay-meta">
......
{% extends 'base.html' %}
{% load staticfiles %}
{% load i18n %}
{% load compress %}
{% block title %}{% trans 'Documents' %} — {{ block.super }}{% 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">
{{ block.super }}
{% compress css %}
<link href="{% static "documents/css/style.less" %}" rel="stylesheet" type="text/less">
{% endcompress %}
{% endblock %}
{% block body %}
<h1 class="main-title">{% trans "Miscellaneous Documents" %}</h1>
<h1>{% 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 class="misc-wrapper">
<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>
</div>
<h1 class="main-title">{% trans "Policy Documents &amp; Annual Reports" %}</h1>
<h1>{% 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'>
<div class="portfolio slider">
<div class="policy-wrapper">
<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") %}
......@@ -45,19 +51,19 @@
</div>
<h1 class="main-title">{% trans "General Meetings" %}</h1>
<h1>{% 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;'>
<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;'>
<select id="alvselect" name="alvselect" class="btn-large btn-style2">
{% for year, meetings in meeting_years|slice:"5:" %}
<option value='{{ year }}'>{{ year }}-{{ year|add:1 }}</option>
<option value=""{{ year }}">{{ year }}-{{ year|add:1 }}</option>
{% endfor %}
</select>
</div>
......@@ -73,7 +79,9 @@
{% 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>
{{ block.super }}
{% compress js %}
<script type="text/javascript" src="{% static "documents/js/policydocuments.js" %}"></script>
<script type="text/javascript" src="{% static "documents/js/generalmeetings.js" %}"></script>
{% endcompress %}
{% endblock %}
\ No newline at end of file
"""
This module registers admin pages for the models
"""
from django.contrib import admin