@@ -1,35 +1,27 @@
import sys
import datetime
import hashlib
import subprocess
import datetime
import sys
from StringIO import StringIO

import xlsxwriter
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.models import User
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.http import HttpResponse, HttpResponseServerError

from django.template.loader import get_template
from django.template import Context
from django.template.defaultfilters import slugify

from django.template.loader import get_template
from django.utils import timezone

from ics import Calendar, Event

from xhtml2pdf import pisa

from django.contrib.auth.models import User
from django.contrib.admin.views.decorators import staff_member_required

import xlsxwriter
from StringIO import StringIO

from django.core.files.storage import default_storage
from django.core.files.base import ContentFile

from config import *



class AuthenticateWithEmail(object):
def authenticate(self, username=None, password=None):
@staticmethod
def authenticate(username=None, password=None):
from models import Member

try:
@@ -39,14 +31,15 @@ def authenticate(self, username=None, password=None):
except Member.DoesNotExist:
return None

def get_user(self, user_id):
@staticmethod
def get_user(user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None


def render_to_pdf_http(request, template_name, renderdict, filename):
def render_to_pdf_http(template_name, renderdict, filename):
"""
Take a string of rendered html and pack it into a pdfand return it thtough http
"""
@@ -61,6 +54,7 @@ def render_to_pdf_http(request, template_name, renderdict, filename):
return HttpResponseServerError()
return response


def render_to_pdf_storage(template_name, renderdict, filename):
"""
Take a string of rendered html and pack it into a pdfand save it
@@ -72,6 +66,7 @@ def render_to_pdf_storage(template_name, renderdict, filename):
pisa.CreatePDF(rendered_html, dest=pdf)
default_storage.save(filename, ContentFile(pdf.getvalue()))


weekday_choices = ((1, "Montag"),
(2, "Dienstag"),
(3, "Mittwoch"),
@@ -82,18 +77,22 @@ def render_to_pdf_storage(template_name, renderdict, filename):

weekdays = dict(weekday_choices)


def get_current_jobs():
from models import Job
return Job.objects.filter(time__gte=timezone.now()).order_by("time")


def get_current_one_time_jobs():
from models import OneTimeJob
return OneTimeJob.objects.filter(time__gte=timezone.now()).order_by("time")


def get_current_recuring_jobs():
from models import RecuringJob
return RecuringJob.objects.filter(time__gte=timezone.now()).order_by("time")


class Swapstd(object):
def __init__(self, f=None, g=None):
if g is None:
@@ -107,14 +106,16 @@ def __enter__(self):
def __exit__(self, *a):
sys.stdout, sys.stderr = self.old


def make_username(firstname, lastname, email):
firstname = slugify(firstname)[:10]
lastname = slugify(lastname)[:10]
email = hashlib.sha1(email).hexdigest()
return ("%s_%s_%s" % (firstname, lastname, email))[:30]


@staff_member_required
def run_in_shell(request, command_string, input=None):
def run_in_shell(command_string, input=None):
p = subprocess.Popen(command_string, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate(input)

@@ -128,103 +129,115 @@ def run_in_shell(request, command_string, input=None):
"%s\n") % (command_string, out, err)
return HttpResponse(res, content_type="text/plain")


def get_status_image(percent=0):
if percent >= 100:
return "circle_full.png"
elif percent >= 75:
return "circle_alomst_full.png"
elif percent >= 50:
return "circle_half.png"
elif percent > 0:
return "circle_almost_empty.png"
else:
return "circle_empty.png"
if percent >= 100:
return "circle_full.png"
elif percent >= 75:
return "circle_alomst_full.png"
elif percent >= 50:
return "circle_half.png"
elif percent > 0:
return "circle_almost_empty.png"
else:
return "circle_empty.png"


def get_status_image_text(percent=0):
if percent >= 100:
return "Fertig"
elif percent >= 75:
return "Dreiviertel"
elif percent >= 50:
return "Halb"
elif percent > 0:
return "Angefangen"
else:
return "Nix"

if percent >= 100:
return "Fertig"
elif percent >= 75:
return "Dreiviertel"
elif percent >= 50:
return "Halb"
elif percent > 0:
return "Angefangen"
else:
return "Nix"


"""
Copys the user defined attributes of a model into another model. It will only copy the fields with are present in both
"""


def attribute_copy(source, target):
for field in target._meta.fields:
if(field.auto_created==False and field.editable==True and field.attname in source.__dict__ and field.attname in target.__dict__):
target.__dict__[field.attname] = source.__dict__[field.attname]
if field.auto_created is False and field.editable is True and field.attname in source.__dict__ and field.attname in target.__dict__:
target.__dict__[field.attname] = source.__dict__[field.attname]


"""
Generates excell for a defined set of fields and a model
"""


def generate_excell(fields, model_instance):
response = HttpResponse(content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=Report.xlsx'
output = StringIO()
workbook = xlsxwriter.Workbook(output)
worksheet_s = workbook.add_worksheet(Config.members_string())
worksheet_s = workbook.add_worksheet("Locos")

col = 0
for field in fields:
parts = field.split('.')
count =1
parts = field.split('.')
count = 1
dbfield = model_instance._meta.get_field(parts[0])
while(count<len(parts)):
while count < len(parts):
dbfield = dbfield.related_model._meta.get_field(parts[count])
count = count + 1
worksheet_s.write_string(0, col, unicode(str(dbfield.verbose_name),"utf-8"))
col = col + 1
count += 1
worksheet_s.write_string(0, col, unicode(str(dbfield.verbose_name), "utf-8"))
col += 1

instances = model_instance.objects.all()

row = 1
for instance in instances:
col =0
col = 0
for field in fields:
parts = field.split('.')
count =1
count = 1
fieldvalue = getattr(instance, parts[0])
while(count<len(parts) and fieldvalue is not None):
while count < len(parts) and fieldvalue is not None:
fieldvalue = getattr(fieldvalue, parts[count])
count = count + 1
count += 1
if fieldvalue is not None:
if isinstance(fieldvalue,unicode):
if isinstance(fieldvalue, unicode):
worksheet_s.write_string(row, col, fieldvalue)
else:
worksheet_s.write_string(row, col, unicode(str(fieldvalue),"utf-8"))
col = col + 1
row = row + 1
worksheet_s.write_string(row, col, unicode(str(fieldvalue), "utf-8"))
col += 1
row += 1

workbook.close()
xlsx_data = output.getvalue()
response.write(xlsx_data)
return response


"""
Create a ical string from an job
"""


def genecrate_ical_for_job(job):
c = Calendar()
e = Event()
e.name = Config.organisation_name()+' Einsatz:'+job.type.name
e.name = Config.organisation_name() + ' Einsatz:' + job.type.name
e.location = job.type.location
e.description = job.type.description
e.begin = job.time.strftime('%Y%m%d %H:%M:%S')
e.end = job.time.strftime('%Y%m%d %H:%M:%S')
c.events.append(e)
return str(c).replace("\n","\r\n")+'\r\n'

return str(c).replace("\n", "\r\n") + '\r\n'


def start_of_year():
year = timezone.now().year
return datetime.date(year, 1, 1)



def start_of_next_year():
year = timezone.now().year+1
year = timezone.now().year + 1
return datetime.date(year, 1, 1)
@@ -1,18 +1,16 @@
# -*- coding: utf-8 -*-

from django.conf import settings
import os
import re

from django.contrib.auth.models import Permission
from django.contrib.sites.shortcuts import get_current_site
from django.core import mail
from django.template.loader import get_template
from django.template import Context
from django.core.mail import EmailMultiAlternatives
from django.db.models import Q
from django.contrib.auth.models import User, Permission
from django.contrib.sites.shortcuts import get_current_site
import os, re


from juntagrico.helpers import *
from juntagrico.config import *


def get_server(server):
site_from_env = os.getenv("ORTOLOCO_TEMPLATE_SERVERURL")
@@ -23,6 +21,7 @@ def get_server(server):
return site_from_db
return server


# sends mail only to specified email-addresses if dev mode
def send_mail(subject, message, from_email, to_emails):
okmails = []
@@ -70,21 +69,24 @@ def send_mail_multi(email_multi_message):

def send_new_member_in_activityarea_to_operations(area, member):
send_mail('Neues Mitglied im Taetigkeitsbereich ' + area.name,
'Soeben hat sich ' + member.first_name + " " + member.last_name + ' in den Taetigkeitsbereich ' + area.name + ' eingetragen', Config.info_email(), [area.coordinator.email])
'Soeben hat sich ' + member.first_name + " " + member.last_name + ' in den Taetigkeitsbereich ' + area.name + ' eingetragen',
Config.info_email(), [area.coordinator.email])


def send_contact_form(subject, message, member, copy_to_member):
send_mail('Anfrage per '+Config.adminportal_name()+': ' + subject, message, member.email, [Config.info_email()])
send_mail('Anfrage per ' + Config.adminportal_name() + ': ' + subject, message, member.email, [Config.info_email()])
if copy_to_member:
send_mail('Anfrage per '+Config.adminportal_name()+': ' + subject, message, member.email, [member.email])

send_mail('Anfrage per ' + Config.adminportal_name() + ': ' + subject, message, member.email, [member.email])


def send_contact_member_form(subject, message, member, contact_member, copy_to_member, attachments):
msg = EmailMultiAlternatives('Nachricht per ' + Config.adminportal_name() +': ' + subject, message, member.email, [contact_member.email], headers={'Reply-To': member.email})
msg = EmailMultiAlternatives('Nachricht per ' + Config.adminportal_name() + ': ' + subject, message, member.email,
[contact_member.email], headers={'Reply-To': member.email})
for attachment in attachments:
msg.attach(attachment.name, attachment.read())
send_mail_multi(msg)
if copy_to_member:
send_mail('Nachricht per ' + Config.adminportal_name() +': ' + subject, message, member.email, [member.email])
send_mail('Nachricht per ' + Config.adminportal_name() + ': ' + subject, message, member.email, [member.email])


def send_welcome_mail(email, password, hash, server):
@@ -93,7 +95,7 @@ def send_welcome_mail(email, password, hash, server):

# reset password so we can send it to him
d = {
'subject': 'Willkommen bei '+Config.organisation_name(),
'subject': 'Willkommen bei ' + Config.organisation_name(),
'username': email,
'password': password,
'hash': hash,
@@ -103,11 +105,12 @@ def send_welcome_mail(email, password, hash, server):
text_content = plaintext.render(d)
html_content = htmly.render(d)

msg = EmailMultiAlternatives('Willkommen bei '+Config.organisation_name(), text_content, Config.info_email(), [email])
msg = EmailMultiAlternatives('Willkommen bei ' + Config.organisation_name(), text_content, Config.info_email(),
[email])
msg.attach_alternative(html_content, "text/html")
send_mail_multi(msg)


def send_share_created_mail(share, server):
plaintext = get_template('mails/share_created_mail.txt')
htmly = get_template('mails/share_created_mail.html')
@@ -121,21 +124,22 @@ def send_share_created_mail(share, server):
text_content = plaintext.render(d)
html_content = htmly.render(d)
perm = Permission.objects.get(codename='is_book_keeper')
users = User.objects.filter(Q(groups__permissions=perm) | Q(user_permissions=perm) ).distinct()
users = User.objects.filter(Q(groups__permissions=perm) | Q(user_permissions=perm)).distinct()
emails = []
for user in users:
emails.append(user.member.email)
msg = EmailMultiAlternatives('Neuer Anteilschein erstellt', text_content, Config.info_email(), emails)
msg.attach_alternative(html_content, "text/html")
send_mail_multi(msg)


def send_been_added_to_subscription(email, password, name, shares, hash, server):
plaintext = get_template('mails/welcome_added_mail.txt')
htmly = get_template('mails/welcome_added_mail.html')

# reset password so we can send it to him
d = {
'subject': 'Willkommen bei '+Config.organisation_name(),
'subject': 'Willkommen bei ' + Config.organisation_name(),
'username': email,
'name': name,
'password': password,
@@ -147,7 +151,8 @@ def send_been_added_to_subscription(email, password, name, shares, hash, server)
text_content = plaintext.render(d)
html_content = htmly.render(d)

msg = EmailMultiAlternatives('Willkommen bei '+Config.organisation_name(), text_content, Config.info_email(), [email])
msg = EmailMultiAlternatives('Willkommen bei ' + Config.organisation_name(), text_content, Config.info_email(),
[email])
msg.attach_alternative(html_content, "text/html")
send_mail_multi(msg)

@@ -180,7 +185,7 @@ def send_filtered_mail(subject, message, text_message, emails, server, attachmen
def send_mail_password_reset(email, password, server):
plaintext = get_template('mails/password_reset_mail.txt')
htmly = get_template('mails/password_reset_mail.html')
subject = 'Dein neues '+Config.organisation_name()+' Passwort'
subject = 'Dein neues ' + Config.organisation_name() + ' Passwort'

d = {
'subject': subject,
@@ -202,21 +207,23 @@ def send_job_reminder(emails, job, participants, server):
htmly = get_template('mails/job_reminder_mail.html')
coordinator = job.typeactivityarea.coordinator
contact = coordinator.first_name + " " + coordinator.last_name + ": " + job.typeactivityarea.contact()

d = {
'job': job,
'participants': participants,
'serverurl': "http://" + get_server(server),
'contact' : contact
'contact': contact
}

text_content = plaintext.render(d)
html_content = htmly.render(d)

msg = EmailMultiAlternatives(Config.organisation_name()+" - Job-Erinnerung", text_content, Config.info_email(), emails)
msg = EmailMultiAlternatives(Config.organisation_name() + " - Job-Erinnerung", text_content, Config.info_email(),
emails)
msg.attach_alternative(html_content, "text/html")
send_mail_multi(msg)


def send_job_canceled(emails, job, server):
plaintext = get_template('mails/job_canceled_mail.txt')
htmly = get_template('mails/job_canceled_mail.html')
@@ -229,10 +236,12 @@ def send_job_canceled(emails, job, server):
text_content = plaintext.render(d)
html_content = htmly.render(d)

msg = EmailMultiAlternatives(Config.organisation_name()+" - Job-Abgesagt", text_content, Config.info_email(), emails)
msg = EmailMultiAlternatives(Config.organisation_name() + " - Job-Abgesagt", text_content, Config.info_email(),
emails)
msg.attach_alternative(html_content, "text/html")
send_mail_multi(msg)


def send_job_time_changed(emails, job, server):
plaintext = get_template('mails/job_time_changed_mail.txt')
htmly = get_template('mails/job_time_changed_mail.html')
@@ -244,14 +253,14 @@ def send_job_time_changed(emails, job, server):

text_content = plaintext.render(d)
html_content = htmly.render(d)
# ical_content = genecrate_ical_for_job(job)
# ical_content = genecrate_ical_for_job(job)

msg = EmailMultiAlternatives(Config.organisation_name()+" - Job-Zeit geändert", text_content, Config.info_email(), emails)
msg = EmailMultiAlternatives(Config.organisation_name() + " - Job-Zeit geändert", text_content, Config.info_email(),
emails)
msg.attach_alternative(html_content, "text/html")
# msg.attach("einsatz.ics", ical_content, "text/calendar")
# msg.attach("einsatz.ics", ical_content, "text/calendar")
send_mail_multi(msg)



def send_job_signup(emails, job, server):
plaintext = get_template('mails/job_signup_mail.txt')
@@ -266,14 +275,15 @@ def send_job_signup(emails, job, server):
html_content = htmly.render(d)
ical_content = genecrate_ical_for_job(job)

msg = EmailMultiAlternatives(Config.organisation_name()+" - fĂĽr Job Angemeldet", text_content, Config.info_email(), emails)
msg = EmailMultiAlternatives(Config.organisation_name() + " - fĂĽr Job Angemeldet", text_content,
Config.info_email(), emails)
msg.attach_alternative(html_content, "text/html")
msg.attach("einsatz.ics", ical_content, "text/calendar")
print repr(msg.message().as_string())
print repr(os.linesep)
# send_mail_multi(msg)
# send_mail_multi(msg)



def send_depot_changed(emails, depot, server):
plaintext = get_template('mails/depot_changed_mail.txt')
htmly = get_template('mails/depot_changed_mail.html')
@@ -286,6 +296,7 @@ def send_depot_changed(emails, depot, server):
text_content = plaintext.render(d)
html_content = htmly.render(d)

msg = EmailMultiAlternatives(Config.organisation_name()+" - Depot geändert", text_content, Config.info_email(), emails)
msg = EmailMultiAlternatives(Config.organisation_name() + " - Depot geändert", text_content, Config.info_email(),
emails)
msg.attach_alternative(html_content, "text/html")
send_mail_multi(msg)
@@ -1,21 +1,18 @@
from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import BaseCommand

from juntagrico.models import *



class Command(BaseCommand):

# entry point used by manage.py
def handle(self, *args, **options):
for user in User.objects.all():
if user.is_superuser:
signals.post_save.disconnect(Member.create, sender=Member)
member = Member.objects.create(user=user, first_name="super", last_name="duper", email=user.email, addr_street="superstreet", addr_zipcode="8000",
addr_location="SuperCity", phone="012345678", confirmed=True)
member.save()
user.member = member
user.save()
signals.post_save.connect(Member.create, sender=Member)


for user in User.objects.all():
if user.is_superuser:
signals.post_save.disconnect(Member.create, sender=Member)
member = Member.objects.create(user=user, first_name="super", last_name="duper", email=user.email,
addr_street="superstreet", addr_zipcode="8000",
addr_location="SuperCity", phone="012345678", confirmed=True)
member.save()
user.member = member
user.save()
signals.post_save.connect(Member.create, sender=Member)
@@ -1,17 +1,9 @@
from django.core.management.base import BaseCommand, CommandError
from django.utils import timezone
from django.conf import settings
from django.core.management.base import BaseCommand

from juntagrico.models import *
from juntagrico.helpers import *
from juntagrico.mailer import *
from juntagrico.config import *

import datetime


class Command(BaseCommand):

def add_arguments(self, parser):

# Named (optional) arguments
@@ -33,95 +25,94 @@ def add_arguments(self, parser):

# entry point used by manage.py
def handle(self, *args, **options):
if not options['force'] and timezone.now().weekday()!=settings.DEPOT_LIST_GENERATION_DAY:
if not options['force'] and timezone.now().weekday() != settings.DEPOT_LIST_GENERATION_DAY:
print "not the specified day for depot list generation, use --force to override"
return
if options['future'] or timezone.now().weekday()==settings.DEPOT_LIST_GENERATION_DAY:

if options['future'] or timezone.now().weekday() == settings.DEPOT_LIST_GENERATION_DAY:
future_subscriptions = Subscription.objects.exclude(future_depot__isnull=True)
for subscription in future_subscriptions:
subscription.depot=subscription.future_depot
subscription.future_depot=None
subscription.depot = subscription.future_depot
subscription.future_depot = None
subscription.save()
emails = []
for member in subscription.recipients():
emails.append(member.email)
send_depot_changed(emails,subscription.depot,Config.server_url())
send_depot_changed(emails, subscription.depot, Config.server_url())

if options['force'] and not options['future']:
print "future depots ignored, use --future to override"
Subscription.fill_sizes_cache()

depots = Depot.objects.all().order_by("code")

subscription_names = []
for subscription_size in SubscriptionSize.objects.filter(depot_list=True).order_by('size'):
subscription_names.append(subscription_size.name)

categories = []
types =[]
types = []
for category in ExtraSubscriptionCategory.objects.all().order_by("sort_order"):
cat={}
cat["name"]= category.name
cat["description"] = category.description
count = 0
for extra_subscription in ExtraSubscriptionType.objects.all().filter(category = category).order_by("sort_order"):
count+=1
type={}
type["name"] = extra_subscription.name
type["size"] = extra_subscription.size
type["last"]=False
types.append(type)
type["last"]=True
cat["count"] = count
categories.append(cat)
cat = {"name": category.name, "description": category.description}
count = 0
for extra_subscription in ExtraSubscriptionType.objects.all().filter(category=category).order_by(
"sort_order"):
count += 1
type = {"name": extra_subscription.name, "size": extra_subscription.size, "last": False}
types.append(type)
# noinspection PyUnboundLocalVariable
type["last"] = True
cat["count"] = count
categories.append(cat)

overview = {
'Dienstag': None,
'Donnerstag': None,
'all': None
}

count = len(types)+2
overview["Dienstag"] = [0]*count
overview["Donnerstag"] = [0]*count
overview["all"] = [0]*count
count = len(types) + 2
overview["Dienstag"] = [0] * count
overview["Donnerstag"] = [0] * count
overview["all"] = [0] * count

all = overview.get('all')

for depot in depots:
depot.fill_overview_cache()
depot.fill_active_subscription_cache()
row = overview.get(depot.get_weekday_display())
count=0
count = 0
# noinspection PyTypeChecker
while count < len(row):
row[count] += depot.overview_cache[count]
all[count] += depot.overview_cache[count]
count+=1;
count += 1

insert_point = len(subscription_names)
overview["Dienstag"].insert(insert_point, 0)
overview["Donnerstag"].insert(insert_point, 0)
overview["all"].insert(insert_point, 0)
index=0

index = 0
for subscription_size in SubscriptionSize.objects.filter(depot_list=True).order_by('size'):
overview["Dienstag"][insert_point]=overview["Dienstag"][insert_point]+ subscription_size.size*overview["Dienstag"][index]
overview["Donnerstag"][insert_point]=overview["Donnerstag"][insert_point]+ subscription_size.size*overview["Donnerstag"][index]
overview["all"][insert_point]=overview["all"][insert_point]+ subscription_size.size*overview["all"][index]
index+=1

overview["Dienstag"][insert_point] = overview["Dienstag"][insert_point] + subscription_size.size * \
overview["Dienstag"][index]
overview["Donnerstag"][insert_point] = overview["Donnerstag"][insert_point] + subscription_size.size * \
overview["Donnerstag"][index]
overview["all"][insert_point] = overview["all"][insert_point] + subscription_size.size * overview["all"][
index]
index += 1

renderdict = {
"overview": overview,
"depots": depots,
"subscription_names": subscription_names,
"categories" : categories,
"types" : types,
"categories": categories,
"types": types,
"datum": timezone.now(),
"cover_sheets": settings.DEPOT_LIST_COVER_SHEETS,
"depot_overviews": settings.DEPOT_LIST_OVERVIEWS,
}

render_to_pdf_storage( "exports/all_depots.html", renderdict, 'dpl.pdf')


render_to_pdf_storage("exports/all_depots.html", renderdict, 'dpl.pdf')
@@ -1,11 +1,6 @@
from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import BaseCommand

from juntagrico.models import *
from juntagrico.config import *
from django.utils import timezone
import datetime
from juntagrico.mailer import send_job_reminder
from django.utils import timezone


class Command(BaseCommand):
@@ -26,5 +21,3 @@ def handle(self, *args, **options):
job.reminder_sent = True
job.save()
print("reminder sent for job " + str(job.id))


@@ -25,7 +25,7 @@ def m2m(m2mrel):
# source_ct = ContentType.objects.get_for_model(source_model)
target_ct = ContentType.objects.get_for_model(target_model)

def callback(instance, action, pk_set, **kwds):
def callback(instance, action, pk_set):
if not action.startswith("post_"):
return
action = "m2m" + action[4:]
@@ -52,7 +52,7 @@ def fk(rel):
fieldname = rel.field.name
target_ct = ContentType.objects.get_for_model(target_model)

def callback(instance, **kwds):
def callback(instance):
target_obj = getattr(instance, fieldname)
kwds = dict(action="fk_set", field=fieldname, source_object=instance)
# ContentType errors out when passing a target_ct with a null object.
@@ -1,17 +1,14 @@
# encoding: utf-8

import datetime
import time

from django.core import validators
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import signals, Q
from django.utils import timezone
from django.db.models import signals
from polymorphic.models import PolymorphicModel

import helpers
from config import *
import model_audit
from juntagrico.mailer import *

@@ -69,7 +66,8 @@ def fill_overview_cache(self):
for subscription_size in SubscriptionSize.objects.filter(depot_list=True).order_by('size'):
self.overview_cache.append(self.subscription_amounts(self.subscription_cache, subscription_size.name))
for category in ExtraSubscriptionCategory.objects.all().order_by("sort_order"):
for extra_subscription in ExtraSubscriptionType.objects.all().filter(category=category).order_by("sort_order"):
for extra_subscription in ExtraSubscriptionType.objects.all().filter(category=category).order_by(
"sort_order"):
code = extra_subscription.name
self.overview_cache.append(self.extra_subscription(self.subscription_cache, code))

@@ -104,7 +102,7 @@ class Bill(models.Model):
amount = models.FloatField("Betrag", null=False, blank=False)

def __unicode__(self):
return u"%s %s" % (self.ref_number)
return u"%s %s" % self.ref_number

class Meta:
verbose_name = "Rechnung"
@@ -121,7 +119,7 @@ class Payment(models.Model):
amount = models.FloatField("Betrag", null=False, blank=False)

def __unicode__(self):
return u"%s %s" % (self.ref_number)
return u"%s %s" % self.ref_number

class Meta:
verbose_name = "Zahlung"
@@ -167,8 +165,9 @@ class ExtraSubscription(Billable):
"""
Types of extra subscriptions, e.g. eggs, cheese, fruit
"""
main_subscription = models.ForeignKey("Subscription", related_name="extra_subscription_set", null=False, blank=False,
on_delete=models.PROTECT)
main_subscription = models.ForeignKey("Subscription", related_name="extra_subscription_set", null=False,
blank=False,
on_delete=models.PROTECT)
active = models.BooleanField(default=False)
canceled = models.BooleanField("gekĂĽndigt", default=False)
activation_date = models.DateField("Aktivierungssdatum", null=True, blank=True)
@@ -179,14 +178,14 @@ class ExtraSubscription(Billable):
old_active = None

@classmethod
def pre_save(cls, sender, instance, **kwds):
def pre_save(cls, instance):
if instance.old_active != instance.active and instance.old_active is False and instance.deactivation_date is None:
instance.activation_date = timezone.now().date()
elif instance.old_active != instance.active and instance.old_active is True and instance.deactivation_date is None:
instance.deactivation_date = timezone.now().date()

@classmethod
def post_init(cls, sender, instance, **kwds):
def post_init(cls, instance):
instance.old_active = instance.active

def __unicode__(self):
@@ -271,7 +270,8 @@ def paid_shares(self):

@property
def future_extra_subscriptions(self):
return self.extra_subscription_set.filter(Q(active=False, deactivation_date=None) | Q(active=True, canceled=False))
return self.extra_subscription_set.filter(
Q(active=False, deactivation_date=None) | Q(active=True, canceled=False))

@staticmethod
def fill_sizes_cache():
@@ -281,10 +281,10 @@ def fill_sizes_cache():
for size in SubscriptionSize.objects.order_by('size'):
list.append(size.size)
map[size.name] = index
index = index + 1
index += 1
Subscription.sizes_cache = {'list': list,
'map': map,
}
'map': map,
}

def subscription_amount(self, subscription_name):
if Subscription.sizes_cache == {}:
@@ -304,7 +304,8 @@ def subscription_amount_future(self, subscription_name):
index = Subscription.sizes_cache['map'][subscription_name]
if index == len(Subscription.sizes_cache['list']) - 1:
return int(self.future_size / Subscription.sizes_cache['list'][index])
return int((self.future_size % Subscription.sizes_cache['list'][index + 1]) / Subscription.sizes_cache['list'][index])
return int(
(self.future_size % Subscription.sizes_cache['list'][index + 1]) / Subscription.sizes_cache['list'][index])

@staticmethod
def next_extra_change_date():
@@ -350,18 +351,18 @@ def clean(self):
raise ValidationError(u'Deaktivierte Abos koennen nicht wieder aktiviert werden', code='invalid')

@classmethod
def pre_save(cls, sender, instance, **kwds):
def pre_save(cls, instance):
if instance.old_active != instance.active and instance.old_active is False and instance.deactivation_date is None:
instance.activation_date = timezone.now().date()
elif instance.old_active != instance.active and instance.old_active is True and instance.deactivation_date is None:
instance.deactivation_date = timezone.now().date()

@classmethod
def post_init(cls, sender, instance, **kwds):
def post_init(cls, instance):
instance.old_active = instance.active

@classmethod
def pre_delete(cls, sender, instance, **kwds):
def pre_delete(cls, instance):
for member in instance.recipients():
member.subscription = None
member.save()
@@ -393,7 +394,7 @@ class Member(models.Model):
mobile_phone = models.CharField("Mobile", max_length=50, null=True, blank=True)

subscription = models.ForeignKey(Subscription, related_name="members", null=True, blank=True,
on_delete=models.SET_NULL)
on_delete=models.SET_NULL)

confirmed = models.BooleanField("bestätigt", default=False)
reachable_by_email = models.BooleanField("Kontaktierbar von der Job Seite aus", default=False)
@@ -405,7 +406,7 @@ def __unicode__(self):
return self.get_name()

@classmethod
def create(cls, sender, instance, created, **kdws):
def create(cls, instance, created):
"""
Callback to create corresponding member when new user is created.
"""
@@ -418,16 +419,16 @@ def create(cls, sender, instance, created, **kdws):
instance.save()

@classmethod
def post_delete(cls, sender, instance, **kwds):
def post_delete(cls, instance):
instance.user.delete()

@classmethod
def pre_save(cls, sender, instance, **kwds):
def pre_save(cls, instance):
if instance.old_subscription != instance.subscription and instance.subscription is None:
instance.areas = ()

@classmethod
def post_init(cls, sender, instance, **kwds):
def post_init(cls, instance):
instance.old_subscription = None # instance.subscription

class Meta:
@@ -446,13 +447,13 @@ def get_phone(self):

class Share(Billable):
member = models.ForeignKey(Member, null=True, blank=True, on_delete=models.SET_NULL)
paid_date = models.DateField("Bezahlt am", null=True, blank=True);
issue_date = models.DateField("Ausgestellt am", null=True, blank=True);
booking_date = models.DateField("Eingebucht am", null=True, blank=True);
cancelled_date = models.DateField("GekĂĽndigt am", null=True, blank=True);
termination_date = models.DateField("GekĂĽndigt auf", null=True, blank=True);
payback_date = models.DateField("ZurĂĽckbezahlt am", null=True, blank=True);
number = models.IntegerField("Anteilschein Nummer", null=True, blank=True);
paid_date = models.DateField("Bezahlt am", null=True, blank=True)
issue_date = models.DateField("Ausgestellt am", null=True, blank=True)
booking_date = models.DateField("Eingebucht am", null=True, blank=True)
cancelled_date = models.DateField("GekĂĽndigt am", null=True, blank=True)
termination_date = models.DateField("GekĂĽndigt auf", null=True, blank=True)
payback_date = models.DateField("ZurĂĽckbezahlt am", null=True, blank=True)
number = models.IntegerField("Anteilschein Nummer", null=True, blank=True)
notes = models.TextField("Notizen", max_length=1000, default="", blank=True)

def __unicode__(self):
@@ -605,7 +606,7 @@ class Meta:


class RecuringJob(Job):
type= models.ForeignKey(JobType, on_delete=models.PROTECT)
type = models.ForeignKey(JobType, on_delete=models.PROTECT)

@classmethod
def pre_save(cls, sender, instance, **kwds):
@@ -663,7 +664,7 @@ def is_core(self):
return self.job.type.activityarea.core

@classmethod
def pre_save(cls, sender, instance, **kwds):
def pre_save(cls, instance):
instance.core_cache = instance.is_core()

class Meta:
@@ -1,22 +1,16 @@
from django.conf.urls import include, url
from django.contrib import admin
from django.contrib.auth.views import login

from django.conf import settings
from django.views.generic import RedirectView
from django.contrib.auth.views import login, logout
from juntagrico import views as juntagrico
from juntagrico import views_subscription as juntagrico_subscription
from juntagrico import views_admin as juntagrico_admin
from juntagrico import views_subscription as juntagrico_subscription
from juntagrico.personalisation import personal_urls
from django.contrib import admin

import django



urlpatterns = [
#general juntagrico stuff
# general juntagrico stuff
url('^my/home$', juntagrico.my_home),
url('^my/passwort$', juntagrico.my_change_password),
url('^my/passwort$', juntagrico.my_change_password),
url('^my/jobs/(?P<job_id>.*?)/', juntagrico.my_job),
url('^my/teams/(?P<area_id>.*?)/', juntagrico.my_team),
url('^my/profil$', juntagrico.my_profile),
@@ -29,8 +23,8 @@
url('^my/depot/(?P<depot_id>.*?)/', juntagrico.my_depot),
url('^my/neuespasswort$', juntagrico.my_new_password),
url(r'^logout/$', juntagrico.logout_view),
url(r'^accounts/login/$', login),
url(r'^accounts/login/$', login),

# subscription related juntagrico stuff
url('^my/subscription$', juntagrico_subscription.my_subscription),
url('^my/subscription/(?P<subscription_id>.*?)/aendern$', juntagrico_subscription.my_subscription_change),
@@ -43,7 +37,7 @@
url('^my/create/subscription/cancel$', juntagrico_subscription.cancel_create_subscription),
url('^my/willkommen$', juntagrico_subscription.my_welcome),
url('^my/bestaetigung/(?P<hash>.*?)/', juntagrico_subscription.my_confirm),

# admin related juntagrico stuff
url('^my/mails/send/depot$', juntagrico_admin.send_email_depot),
url('^my/mails/send/area$', juntagrico_admin.send_email_area),
@@ -57,11 +51,11 @@
url('^my/filters/area/(?P<area_id>.*?)/', juntagrico_admin.my_filters_area),
url('^my/subscriptions$', juntagrico_admin.my_subscriptions),
url('^my/subscriptions/depot/(?P<depot_id>.*?)/', juntagrico_admin.my_subscriptions_depot),
#url('^my/depotlisten', juntagrico_admin.my_depotlists),
# url('^my/depotlisten', juntagrico_admin.my_depotlists),
url('^my/exports/depotlisten/(?P<name>.*)', juntagrico_admin.alldepots_list),
url('^my/zukunft', juntagrico_admin.my_future),
url('^my/wechsel/zusatzsubscriptions', juntagrico_admin.my_switch_extras),
url('^my/wechsel/subscriptions', juntagrico_admin.my_switch_subscriptions),
url('^my/wechsel/subscriptions', juntagrico_admin.my_switch_subscriptions),
url('^my/export$', juntagrico_admin.my_export),
url('^my/export/membersfilter$', juntagrico_admin.my_excel_export_members_filter),
url('^my/export/members', juntagrico_admin.my_excel_export_members),
@@ -70,7 +64,6 @@
url('^my/waitinglist', juntagrico_admin.waitinglist),
url('^my/maps', juntagrico_admin.my_maps),


url(r'^my', include(personal_urls)),
url(r'^admin/', include(admin.site.urls)),
]
@@ -1,39 +1,23 @@
# -*- coding: utf-8 -*-

from datetime import date
from collections import defaultdict
from StringIO import StringIO
import string
import random
import re
import math
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render, get_object_or_404, redirect
import string
from datetime import date

from django.contrib import auth
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth import authenticate, login
from django.core.management import call_command
from django.contrib.auth.decorators import login_required
from django.db.models import Count
from django.db import models
from django.utils import timezone
from django.conf import settings

import xlsxwriter
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404

from juntagrico.models import *
from juntagrico.forms import *
from juntagrico.helpers import *
from juntagrico.filters import Filter
from juntagrico.mailer import *
from juntagrico.models import *
from juntagrico.personalisation.personal_utils import enrich_menu_dict

import hashlib

from decorators import primary_member_of_subscription

def password_generator(size=8, chars=string.ascii_uppercase + string.digits): return ''.join(
random.choice(chars) for x in range(size))

def password_generator(size=8, chars=string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for x in range(size))

def get_menu_dict(request):
member = request.user.member
@@ -45,18 +29,18 @@ def filter_to_past_assignments(assignments):
if assignment.job.time.year == date.today().year and assignment.job.time < timezone.now():
res.append(assignment)
return res
subscription_size=0

subscription_size = 0
if member.subscription is not None:
partner_assignments = []
for subscription_member in member.subscription.recipients():
if subscription_member == member: continue
partner_assignments.extend(filter_to_past_assignments(Assignment.objects.filter(member=subscription_member)))
if subscription_member == member:
continue
partner_assignments.extend(
filter_to_past_assignments(Assignment.objects.filter(member=subscription_member)))

userassignments = filter_to_past_assignments(Assignment.objects.filter(member=member))
subscription_size = member.subscription.size * 10

# amount of assignments shown => round up if needed never down
assignmentsrange = range(0, max(userassignments.__len__(), int(math.ceil(member.subscription.size * 10 / member.subscription.members.count()))))
assignmentsrange = range(0, max(subscription_size, len(userassignments) + len(partner_assignments)))

for assignment in Assignment.objects.all().filter(member=member).order_by("job__time"):
@@ -76,7 +60,8 @@ def filter_to_past_assignments(assignments):
'userassignments_total': len(userassignments),
'userassignemnts_core': len([assignment for assignment in userassignments if assignment.is_core()]),
'partner_assignments_total': len(userassignments) + len(partner_assignments),
'partner_assignments_core': len(userassignments) + len([assignment for assignment in partner_assignments if assignment.is_core()]),
'partner_assignments_core': len(userassignments) + len(
[assignment for assignment in partner_assignments if assignment.is_core()]),
'subscription_size': subscription_size,
'next_jobs': next_jobs,
'can_filter_members': request.user.has_perm('juntagrico.can_filter_members'),
@@ -85,9 +70,9 @@ def filter_to_past_assignments(assignments):
'operation_group': request.user.has_perm('juntagrico.is_operations_group'),
'depot_admin': depot_admin,
'area_admin': area_admin,
'depot_list_url': settings.MEDIA_URL+ settings.MEDIA_ROOT +"/dpl.pdf",
'depot_list_url': settings.MEDIA_URL + settings.MEDIA_ROOT + "/dpl.pdf",
}
enrich_menu_dict(request,menu_dict)
enrich_menu_dict(request, menu_dict)
return menu_dict


@@ -99,7 +84,8 @@ def my_home(request):

next_jobs = set(get_current_jobs()[:7])
pinned_jobs = set(Job.objects.filter(pinned=True, time__gte=timezone.now()))
next_activityday = set(RecuringJob.objects.filter(type__name="Aktionstag", time__gte=timezone.now()).order_by("time")[:2])
next_activityday = set(
RecuringJob.objects.filter(type__name="Aktionstag", time__gte=timezone.now()).order_by("time")[:2])
renderdict = get_menu_dict(request)
renderdict.update({
'jobs': sorted(next_jobs.union(pinned_jobs).union(next_activityday), key=lambda job: job.time),
@@ -128,8 +114,7 @@ def my_job(request, job_id):
# redirect to same page such that refresh in the browser or back
# button does not trigger a resubmission of the form
return HttpResponseRedirect('my/jobs')



all_participants = Member.objects.filter(assignment__job=job)
number_of_participants = len(all_participants)
unique_participants = all_participants.annotate(assignment_for_job=Count('id')).distinct()
@@ -139,31 +124,28 @@ def my_job(request, job_id):
for member in unique_participants:
name = u'{} {}'.format(member.first_name, member.last_name)
if member.assignment_for_job == 2:
name = name + u' (mit einer weiteren Person)'
name += u' (mit einer weiteren Person)'
elif member.assignment_for_job > 2:
name = name + u' (mit {} weiteren Personen)'.format(member.assignment_for_job - 1)
name += u' (mit {} weiteren Personen)'.format(member.assignment_for_job - 1)
contact_url = u'/my/kontakt/member/{}/{}/'.format(member.id, job_id)
reachable = member.reachable_by_email==True or request.user.is_staff or job.typeactivityarea.coordinator==member
reachable = member.reachable_by_email is True or request.user.is_staff or job.typeactivityarea.coordinator == member
participants_summary.append((name, None, contact_url, reachable))
emails.append(member.email)



slotrange = range(0, job.slots)
allowed_additional_participants = range(1, job.slots - number_of_participants + 1)
job_fully_booked = len(allowed_additional_participants) == 0
job_is_in_past = job.end_time() < timezone.now()
job_is_running = job.start_time() < timezone.now()
job_canceled = job.canceled
can_subscribe = not(job_fully_booked or job_is_in_past or job_is_running or job_canceled)
can_subscribe = not (job_fully_booked or job_is_in_past or job_is_running or job_canceled)

renderdict = get_menu_dict(request)
jobendtime = job.end_time()
renderdict.update({
'admin': request.user.is_staff or job.typeactivityarea.coordinator==member,
'admin': request.user.is_staff or job.typeactivityarea.coordinator == member,
'emails': "\n".join(emails),
'number_of_participants': number_of_participants,
'participants_summary': participants_summary,
'participants_summary': participants_summary,
'job': job,
'slotrange': slotrange,
'allowed_additional_participants': allowed_additional_participants,
@@ -252,9 +234,6 @@ def my_pastjobs(request):
return render(request, "pastjobs.html", renderdict)





@login_required
def my_team(request, area_id):
"""
@@ -265,15 +244,13 @@ def my_team(request, area_id):

otjobs = get_current_one_time_jobs().filter(activityarea=area_id)
rjobs = get_current_recuring_jobs().filter(type__in=job_types)

jobs = list(rjobs)

if len(otjobs) > 0:
jobs.extend(list(otjobs))
jobs.sort(key=lambda job: job.time)



renderdict = get_menu_dict(request)
renderdict.update({
'team': get_object_or_404(ActivityArea, id=int(area_id)),
@@ -335,13 +312,14 @@ def my_contact(request):
})
return render(request, "contact.html", renderdict)


@login_required
def my_contact_member(request, member_id, job_id):
"""
member contact form
"""
member = request.user.member
contact_member = get_object_or_404(Member, id=int(member_id))#Member.objects.all().filter(id = member_id)
contact_member = get_object_or_404(Member, id=int(member_id)) # Member.objects.all().filter(id = member_id)
is_sent = False

if request.method == "POST":
@@ -351,12 +329,13 @@ def my_contact_member(request, member_id, job_id):
while request.FILES.get("image-" + str(index)) is not None:
attachments.append(request.FILES.get("image-" + str(index)))
index += 1
send_contact_member_form(request.POST.get("subject"), request.POST.get("message"), member, contact_member, request.POST.get("copy"), attachments)
send_contact_member_form(request.POST.get("subject"), request.POST.get("message"), member, contact_member,
request.POST.get("copy"), attachments)
is_sent = True
job = Job.objects.filter(id=job_id)[0]
renderdict = get_menu_dict(request)
renderdict.update({
'admin': request.user.is_staff or job.typeactivityarea.coordinator==member,
renderdict.update({
'admin': request.user.is_staff or job.typeactivityarea.coordinator == member,
'usernameAndEmail': member.first_name + " " + member.last_name + "<" + member.email + ">",
'member_id': member_id,
'member_name': contact_member.first_name + " " + contact_member.last_name,
@@ -373,7 +352,7 @@ def my_profile(request):
if request.method == 'POST':
memberform = MemberProfileForm(request.POST, instance=member)
if memberform.is_valid():
#set all fields of user
# set all fields of user
member.first_name = memberform.cleaned_data['first_name']
member.last_name = memberform.cleaned_data['last_name']
member.email = memberform.cleaned_data['email']

Large diffs are not rendered by default.

Large diffs are not rendered by default.