Format core

This commit is contained in:
Pierre Brunet 2017-06-12 09:42:03 +02:00
parent 4f4ea5dde9
commit e7de8b2aec
20 changed files with 515 additions and 415 deletions

View File

@ -33,6 +33,7 @@ admin.site.unregister(AuthGroup)
admin.site.register(RealGroup)
admin.site.register(Page)
@admin.register(SithFile)
class SithFileAdmin(admin.ModelAdmin):
form = make_ajax_form(SithFile, {

View File

@ -23,9 +23,9 @@
#
from django.apps import AppConfig
from django.dispatch import receiver
from django.core.signals import request_started
class SithConfig(AppConfig):
name = 'core'
verbose_name = "Core app of the Sith"
@ -48,4 +48,3 @@ class SithConfig(AppConfig):
request_started.connect(clear_cached_groups, weak=False, dispatch_uid="clear_cached_groups")
request_started.connect(clear_cached_memberships, weak=False, dispatch_uid="clear_cached_memberships")
# TODO: there may be a need to add more cache clearing

View File

@ -31,16 +31,19 @@ from club.models import Club
from counter.models import Product, Counter
from accounting.models import ClubAccount, Company
def check_token(request):
return ('counter_token' in request.session.keys() and
request.session['counter_token'] and
Counter.objects.filter(token=request.session['counter_token']).exists())
class RightManagedLookupChannel(LookupChannel):
def check_auth(self, request):
if not request.user.was_subscribed and not check_token(request):
raise PermissionDenied
@register('users')
class UsersLookup(RightManagedLookupChannel):
model = User
@ -54,6 +57,7 @@ class UsersLookup(RightManagedLookupChannel):
def format_item_display(self, item):
return item.get_display_name()
@register('groups')
class GroupsLookup(RightManagedLookupChannel):
model = Group
@ -67,6 +71,7 @@ class GroupsLookup(RightManagedLookupChannel):
def format_item_display(self, item):
return item.name
@register('clubs')
class ClubLookup(RightManagedLookupChannel):
model = Club
@ -80,6 +85,7 @@ class ClubLookup(RightManagedLookupChannel):
def format_item_display(self, item):
return item.name
@register('counters')
class CountersLookup(RightManagedLookupChannel):
model = Counter
@ -90,6 +96,7 @@ class CountersLookup(RightManagedLookupChannel):
def format_item_display(self, item):
return item.name
@register('products')
class ProductsLookup(RightManagedLookupChannel):
model = Product
@ -101,6 +108,7 @@ class ProductsLookup(RightManagedLookupChannel):
def format_item_display(self, item):
return "%s (%s)" % (item.name, item.code)
@register('files')
class SithFileLookup(RightManagedLookupChannel):
model = SithFile
@ -108,6 +116,7 @@ class SithFileLookup(RightManagedLookupChannel):
def get_query(self, q, request):
return self.model.objects.filter(name__icontains=q)[:50]
@register('club_accounts')
class ClubAccountLookup(RightManagedLookupChannel):
model = ClubAccount
@ -118,6 +127,7 @@ class ClubAccountLookup(RightManagedLookupChannel):
def format_item_display(self, item):
return item.name
@register('companies')
class CompaniesLookup(RightManagedLookupChannel):
model = Company

View File

@ -21,4 +21,3 @@
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#

View File

@ -44,7 +44,6 @@ class Command(BaseCommand):
args['precision'] = settings.SASS_PRECISION
return sass.compile(**args)
def is_compilable(self, file, ext_list):
path, ext = os.path.splitext(file)
return ext in ext_list

View File

@ -26,7 +26,7 @@ import os
from datetime import date, datetime
from io import StringIO, BytesIO
from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import BaseCommand
from django.core.management import call_command
from django.conf import settings
from django.db import connection
@ -42,7 +42,7 @@ from subscription.models import Subscription
from counter.models import Customer, ProductType, Product, Counter
from com.models import Sith, Weekmail
from election.models import Election, Role, Candidature, ElectionList
from forum.models import Forum, ForumMessage, ForumTopic
from forum.models import Forum, ForumTopic
class Command(BaseCommand):
@ -258,7 +258,7 @@ Welcome to the wiki page!
PageRev(page=p, title="README", author=skia, content=rm.read()).save()
# Subscription
## Root
# Root
s = Subscription(member=User.objects.filter(pk=root.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0])
s.subscription_start = s.compute_start()
@ -266,7 +266,7 @@ Welcome to the wiki page!
duration=settings.SITH_SUBSCRIPTIONS[s.subscription_type]['duration'],
start=s.subscription_start)
s.save()
## Skia
# Skia
s = Subscription(member=User.objects.filter(pk=skia.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0])
s.subscription_start = s.compute_start()
@ -274,7 +274,7 @@ Welcome to the wiki page!
duration=settings.SITH_SUBSCRIPTIONS[s.subscription_type]['duration'],
start=s.subscription_start)
s.save()
## Counter admin
# Counter admin
s = Subscription(member=User.objects.filter(pk=counter.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0])
s.subscription_start = s.compute_start()
@ -282,7 +282,7 @@ Welcome to the wiki page!
duration=settings.SITH_SUBSCRIPTIONS[s.subscription_type]['duration'],
start=s.subscription_start)
s.save()
## Comptable
# Comptable
s = Subscription(member=User.objects.filter(pk=comptable.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0])
s.subscription_start = s.compute_start()
@ -290,7 +290,7 @@ Welcome to the wiki page!
duration=settings.SITH_SUBSCRIPTIONS[s.subscription_type]['duration'],
start=s.subscription_start)
s.save()
## Richard
# Richard
s = Subscription(member=User.objects.filter(pk=r.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0])
s.subscription_start = s.compute_start()
@ -298,7 +298,7 @@ Welcome to the wiki page!
duration=settings.SITH_SUBSCRIPTIONS[s.subscription_type]['duration'],
start=s.subscription_start)
s.save()
## User
# User
s = Subscription(member=User.objects.filter(pk=subscriber.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0])
s.subscription_start = s.compute_start()
@ -306,7 +306,7 @@ Welcome to the wiki page!
duration=settings.SITH_SUBSCRIPTIONS[s.subscription_type]['duration'],
start=s.subscription_start)
s.save()
## Old subscriber
# Old subscriber
s = Subscription(member=User.objects.filter(pk=old_subscriber.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0])
s.subscription_start = s.compute_start(datetime(year=2012, month=9, day=4))
@ -456,7 +456,7 @@ Welcome to the wiki page!
krophil_profile.save()
krophil.profile_pict = krophil_profile
krophil.save()
## Adding subscription for sli
# Adding subscription for sli
s = Subscription(member=User.objects.filter(pk=sli.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0])
s.subscription_start = s.compute_start()
@ -464,7 +464,7 @@ Welcome to the wiki page!
duration=settings.SITH_SUBSCRIPTIONS[s.subscription_type]['duration'],
start=s.subscription_start)
s.save()
## Adding subscription for Krophil
# Adding subscription for Krophil
s = Subscription(member=User.objects.filter(pk=krophil.pk).first(), subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[0],
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0])
s.subscription_start = s.compute_start()
@ -519,4 +519,3 @@ Welcome to the wiki page!
various.save()
Forum(name="Promos", description="Réservé aux Promos", parent=various).save()
ForumTopic(forum=hall)

View File

@ -23,9 +23,8 @@
#
import os
from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import BaseCommand
from django.core.management import call_command
from django.conf import settings
class Command(BaseCommand):

View File

@ -24,7 +24,7 @@
import re
from mistune import Renderer, InlineGrammar, InlineLexer, Markdown, escape, escape_link
from django.core.urlresolvers import reverse_lazy, reverse
from django.core.urlresolvers import reverse
class SithRenderer(Renderer):
@ -54,13 +54,16 @@ class SithRenderer(Renderer):
src = original_src
else:
width = m.group(1)
if not width.endswith('%'): width += "px"
if not width.endswith('%'):
width += "px"
style = "width: %s; " % width
try:
height = m.group(3)
if not height.endswith('%'): height += "px"
if not height.endswith('%'):
height += "px"
style += "height: %s; " % height
except: pass
except:
pass
else:
params = None
src = original_src
@ -77,6 +80,7 @@ class SithRenderer(Renderer):
return '%s />' % html
return '%s>' % html
class SithInlineGrammar(InlineGrammar):
double_emphasis = re.compile(
r'^\*{2}([\s\S]+?)\*{2}(?!\*)' # **word**
@ -94,6 +98,7 @@ class SithInlineGrammar(InlineGrammar):
r'^<sub>([\s\S]+?)</sub>' # <sub>text</sub>
)
class SithInlineLexer(InlineLexer):
grammar_class = SithInlineGrammar
@ -166,7 +171,8 @@ class SithInlineLexer(InlineLexer):
match = page.search(link)
page = match.group(1) or ""
link = reverse('core:page', kwargs={'page_name': page})
except: pass
except:
pass
try: # Add file:// support for links
file_link = re.compile(
r'^file://(\d*)/?(\S*)?' # file://4000/download
@ -175,9 +181,11 @@ class SithInlineLexer(InlineLexer):
id = match.group(1)
suffix = match.group(2) or ""
link = reverse('core:file_detail', kwargs={'file_id': id}) + suffix
except: pass
except:
pass
return super(SithInlineLexer, self)._process_link(m, link, title)
renderer = SithRenderer(escape=True)
inline = SithInlineLexer(renderer)
@ -222,4 +230,3 @@ Petit *test* _sur_ ^une^ **seule** ^ligne pour voir^
"""
print(markdown(text))

View File

@ -52,4 +52,3 @@ class AuthenticationMiddleware(DjangoAuthenticationMiddleware):
"'account.middleware.AuthenticationMiddleware'."
)
request.user = SimpleLazyObject(lambda: get_cached_user(request))

View File

@ -44,14 +44,17 @@ from datetime import datetime, timedelta, date
import unicodedata
class RealGroupManager(AuthGroupManager):
def get_queryset(self):
return super(RealGroupManager, self).get_queryset().filter(is_meta=False)
class MetaGroupManager(AuthGroupManager):
def get_queryset(self):
return super(MetaGroupManager, self).get_queryset().filter(is_meta=True)
class Group(AuthGroup):
is_meta = models.BooleanField(
_('meta group status'),
@ -69,8 +72,10 @@ class Group(AuthGroup):
"""
return reverse('core:group_list')
class MetaGroup(Group):
objects = MetaGroupManager()
class Meta:
proxy = True
@ -78,11 +83,14 @@ class MetaGroup(Group):
super(MetaGroup, self).__init__(*args, **kwargs)
self.is_meta = True
class RealGroup(Group):
objects = RealGroupManager()
class Meta:
proxy = True
def validate_promo(value):
start_year = settings.SITH_SCHOOL_START_YEAR
delta = (date.today() + timedelta(days=180)).year - start_year
@ -92,6 +100,7 @@ def validate_promo(value):
params={'value': value, 'end': delta},
)
class User(AbstractBaseUser):
"""
Defines the base user class, useable in every app
@ -226,6 +235,7 @@ class User(AbstractBaseUser):
_club_memberships = {}
_group_names = {}
_group_ids = {}
def is_in_group(self, group_name):
"""If the user is in the group passed in argument (as string or by id)"""
group_id = 0
@ -401,7 +411,7 @@ class User(AbstractBaseUser):
Returns the generated username
"""
def remove_accents(data):
return ''.join(x for x in unicodedata.normalize('NFKD', data) if \
return ''.join(x for x in unicodedata.normalize('NFKD', data) if
unicodedata.category(x)[0] == 'L').lower()
user_name = remove_accents(self.first_name[0] + self.last_name).encode('ascii', 'ignore').decode('utf-8')
un_set = [u.username for u in User.objects.all()]
@ -489,6 +499,7 @@ class User(AbstractBaseUser):
infos.save()
return infos
class AnonymousUser(AuthAnonymousUser):
def __init__(self, request):
super(AnonymousUser, self).__init__()
@ -557,6 +568,7 @@ class AnonymousUser(AuthAnonymousUser):
def get_display_name(self):
return _("Visitor")
class Preferences(models.Model):
user = models.OneToOneField(User, related_name="preferences")
receive_weekmail = models.BooleanField(
@ -576,15 +588,19 @@ class Preferences(models.Model):
def get_absolute_url(self):
return self.user.get_absolute_url()
def get_directory(instance, filename):
return '.{0}/{1}'.format(instance.get_parent_path(), filename)
def get_compressed_directory(instance, filename):
return '.{0}/compressed/{1}'.format(instance.get_parent_path(), filename)
def get_thumbnail_directory(instance, filename):
return '.{0}/thumbnail/{1}'.format(instance.get_parent_path(), filename)
class SithFile(models.Model):
name = models.CharField(_('file name'), max_length=256, blank=False)
parent = models.ForeignKey('self', related_name="children", verbose_name=_("parent"), null=True, blank=True)
@ -763,18 +779,22 @@ class SithFile(models.Model):
def __str__(self):
return self.get_parent_path() + "/" + self.name
class LockError(Exception):
"""There was a lock error on the object"""
pass
class AlreadyLocked(LockError):
"""The object is already locked"""
pass
class NotLocked(LockError):
"""The object is not locked"""
pass
class Page(models.Model):
"""
The page class to build a Wiki
@ -792,8 +812,7 @@ class Page(models.Model):
r'^[A-z.+-]+$',
_('Enter a valid page name. This value may contain only '
'unaccented letters, numbers ' 'and ./+/-/_ characters.')
),
],
), ],
blank=False)
parent = models.ForeignKey('self', related_name="children", verbose_name=_("parent"), null=True, blank=True, on_delete=models.SET_NULL)
# Attention: this field may not be valid until you call save(). It's made for fast query, but don't rely on it when
@ -854,7 +873,8 @@ class Page(models.Model):
Performs some needed actions before and after saving a page in database
"""
locked = kwargs.pop('force_lock', False)
if not locked: locked = self.is_locked()
if not locked:
locked = self.is_locked()
if not locked:
raise NotLocked("The page is not locked and thus can not be saved")
self.full_clean()
@ -1003,6 +1023,7 @@ class PageRev(models.Model):
# Don't forget to unlock, otherwise, people will have to wait for the page's timeout
self.page.unset_lock()
class Notification(models.Model):
user = models.ForeignKey(User, related_name='notifications')
url = models.CharField(_("url"), max_length=255)
@ -1015,4 +1036,3 @@ class Notification(models.Model):
if self.param:
return self.get_type_display() % self.param
return self.get_type_display()

View File

@ -27,17 +27,18 @@ from django import template
from django.template.defaultfilters import stringfilter
from django.utils.safestring import mark_safe
from core.scss.processor import ScssProcessor
from django.utils.html import escape
from core.markdown import markdown as md
register = template.Library()
@register.filter(is_safe=False)
@stringfilter
def markdown(text):
return mark_safe("<div class=\"markdown\">%s</div>" % md(text))
@register.filter()
@stringfilter
def datetime_format_python_to_PHP(python_format_string):
@ -51,6 +52,7 @@ def datetime_format_python_to_PHP(python_format_string):
php_format_string = php_format_string.replace(py, php)
return php_format_string
@register.simple_tag()
def scss(path):
"""

View File

@ -24,7 +24,6 @@
from django.test import Client, TestCase
from django.core.urlresolvers import reverse
from django.contrib.auth.models import Group
from django.core.management import call_command
from core.models import User, Group, Page
@ -34,6 +33,7 @@ to run these tests :
python3 manage.py test
"""
class UserRegistrationTest(TestCase):
def setUp(self):
try:
@ -185,6 +185,7 @@ class UserRegistrationTest(TestCase):
self.assertTrue(response.status_code == 200)
self.assertTrue("""<p>Votre nom d\\'utilisateur et votre mot de passe ne correspondent pas. Merci de r\\xc3\\xa9essayer.</p>""" in str(response.content))
class PageHandlingTest(TestCase):
def setUp(self):
try:
@ -260,7 +261,7 @@ class PageHandlingTest(TestCase):
'name': 'guy',
'owner_group': '1',
})
r = self.client.post(reverse('core:page_edit', kwargs={'page_name': 'guy'}), {
self.client.post(reverse('core:page_edit', kwargs={'page_name': 'guy'}), {
'title': 'Bibou',
'content':
'''Guy *bibou*
@ -285,6 +286,7 @@ http://git.an
# - changing a page's parent --> check that page's children's full_name
# - changing the different groups of the page
class FileHandlingTest(TestCase):
def setUp(self):
try:
@ -310,4 +312,3 @@ class FileHandlingTest(TestCase):
response = self.client.get(reverse("core:file_detail", kwargs={"file_id": self.subscriber.home.id}))
self.assertTrue(response.status_code == 200)
self.assertTrue("ls</a>" in str(response.content))

View File

@ -22,7 +22,7 @@
#
#
from django.conf.urls import url, include
from django.conf.urls import url
from core.views import *

View File

@ -27,9 +27,10 @@ import re
# Image utils
from io import BytesIO
from datetime import datetime, timezone, date
from datetime import date
from PIL import Image, ExifTags
from PIL import ExifTags
# from exceptions import IOError
import PIL
from django.conf import settings
@ -59,6 +60,7 @@ def get_start_of_semester(d=date.today()):
else:
return start2
def get_semester(d=date.today()):
start = get_start_of_semester(d)
if start.month <= 6:
@ -66,6 +68,7 @@ def get_semester(d=date.today()):
else:
return "A" + str(start.year)[-2:]
def scale_dimension(width, height, long_edge):
if width > height:
ratio = long_edge * 1. / width
@ -73,6 +76,7 @@ def scale_dimension(width, height, long_edge):
ratio = long_edge * 1. / height
return int(width * ratio), int(height * ratio)
def resize_image(im, edge, format):
(w, h) = im.size
(width, height) = scale_dimension(w, h, long_edge=edge)
@ -85,9 +89,11 @@ def resize_image(im, edge, format):
im.save(fp=content, format=format.upper(), quality=90, optimize=True, progressive=True)
return ContentFile(content.getvalue())
def exif_auto_rotate(image):
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation]=='Orientation' : break
if ExifTags.TAGS[orientation] == 'Orientation':
break
exif = dict(image._getexif().items())
if exif[orientation] == 3:
@ -99,6 +105,7 @@ def exif_auto_rotate(image):
return image
def doku_to_markdown(text):
"""This is a quite correct doku translator"""
text = re.sub(r'([^:]|^)\/\/(.*?)\/\/', r'*\2*', text) # Italic (prevents protocol:// conflict)
@ -164,12 +171,14 @@ def doku_to_markdown(text):
quote_level -= 1
final_newline = True
new_text.append("> " * final_quote_level + line) # Finally append the line
if final_newline: new_text.append("\n") # Add a new line to ensure the separation between the quote and the following text
if final_newline:
new_text.append("\n") # Add a new line to ensure the separation between the quote and the following text
else:
new_text.append(line)
return "\n".join(new_text)
def bbcode_to_markdown(text):
"""This is a very basic BBcode translator"""
text = re.sub(r'\[b\](.*?)\[\/b\]', r'**\1**', text, flags=re.DOTALL) # Bold
@ -205,9 +214,9 @@ def bbcode_to_markdown(text):
quote_level -= 1
final_newline = True
new_text.append("> " * final_quote_level + line) # Finally append the line
if final_newline: new_text.append("\n") # Add a new line to ensure the separation between the quote and the following text
if final_newline:
new_text.append("\n") # Add a new line to ensure the separation between the quote and the following text
else:
new_text.append(line)
return "\n".join(new_text)

View File

@ -23,29 +23,28 @@
#
# This file contains all the views that concern the page model
from django.shortcuts import render, redirect, get_object_or_404
from django.shortcuts import redirect
from django.views.generic import ListView, DetailView, TemplateView
from django.views.generic.edit import UpdateView, CreateView, FormMixin, DeleteView
from django.views.generic.edit import UpdateView, FormMixin, DeleteView
from django.views.generic.detail import SingleObjectMixin
from django.contrib.auth.decorators import login_required, permission_required
from django.forms.models import modelform_factory
from django.forms import CheckboxSelectMultiple
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.http import HttpResponse
from django.core.servers.basehttp import FileWrapper
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.core.exceptions import PermissionDenied
from django import forms
import os
from ajax_select import make_ajax_form, make_ajax_field
from ajax_select import make_ajax_field
from core.models import SithFile, RealGroup, Notification
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, can_view, not_found
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, can_view, not_found
from counter.models import Counter
def send_file(request, file_id, file_class=SithFile, file_attr="file"):
"""
Send a file through Django without loading the whole file into
@ -70,6 +69,7 @@ def send_file(request, file_id, file_class=SithFile, file_attr="file"):
response['Content-Disposition'] = ('inline; filename="%s"' % f.name).encode('utf-8')
return response
class AddFilesForm(forms.Form):
folder_name = forms.CharField(label=_("Add a new folder"), max_length=30, required=False)
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}), label=_("Files"),
@ -100,6 +100,7 @@ class AddFilesForm(forms.Form):
if not u.notifications.filter(type="FILE_MODERATION", viewed=False).exists():
Notification(user=u, url=reverse("core:file_moderation"), type="FILE_MODERATION").save()
class FileListView(ListView):
template_name = 'core/file_list.jinja'
context_object_name = "file_list"
@ -114,6 +115,7 @@ class FileListView(ListView):
kwargs['popup'] = 'popup'
return kwargs
class FileEditView(CanEditMixin, UpdateView):
model = SithFile
pk_url_kwarg = "file_id"
@ -138,6 +140,7 @@ class FileEditView(CanEditMixin, UpdateView):
kwargs['popup'] = 'popup'
return kwargs
class FileEditPropForm(forms.ModelForm):
class Meta:
model = SithFile
@ -147,6 +150,7 @@ class FileEditPropForm(forms.ModelForm):
view_groups = make_ajax_field(SithFile, 'view_groups', 'groups', help_text="", label=_("view group"))
recursive = forms.BooleanField(label=_("Apply rights recursively"), required=False)
class FileEditPropView(CanEditPropMixin, UpdateView):
model = SithFile
pk_url_kwarg = "file_id"
@ -175,6 +179,7 @@ class FileEditPropView(CanEditPropMixin, UpdateView):
kwargs['popup'] = 'popup'
return kwargs
class FileView(CanViewMixin, DetailView, FormMixin):
"""This class handle the upload of new files into a folder"""
model = SithFile
@ -237,6 +242,7 @@ class FileView(CanViewMixin, DetailView, FormMixin):
kwargs['clipboard'] = SithFile.objects.filter(id__in=self.request.session['clipboard'])
return kwargs
class FileDeleteView(CanEditPropMixin, DeleteView):
model = SithFile
pk_url_kwarg = "file_id"
@ -258,6 +264,7 @@ class FileDeleteView(CanEditPropMixin, DeleteView):
kwargs['popup'] = 'popup'
return kwargs
class FileModerationView(TemplateView):
template_name = "core/file_moderation.jinja"
@ -266,6 +273,7 @@ class FileModerationView(TemplateView):
kwargs['files'] = SithFile.objects.filter(is_moderated=False)[:100]
return kwargs
class FileModerateView(CanEditPropMixin, SingleObjectMixin):
model = SithFile
pk_url_kwarg = "file_id"
@ -278,4 +286,3 @@ class FileModerateView(CanEditPropMixin, SingleObjectMixin):
if 'next' in self.request.GET.keys():
return redirect(self.request.GET['next'])
return redirect('core:file_moderation')

View File

@ -22,22 +22,24 @@
#
#
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, UserChangeForm
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django import forms
from django.conf import settings
from django.db import transaction
from django.core.exceptions import ValidationError
from django.contrib.auth import logout, login, authenticate
from django.forms import CheckboxSelectMultiple, Select, DateInput, TextInput, DateTimeInput, Textarea
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget
from ajax_select.fields import AutoCompleteSelectField
import logging
import re
from core.models import User, Page, RealGroup, SithFile
from core.models import User, Page, SithFile
from core.utils import resize_image
from io import BytesIO
from PIL import Image
# Widgets
@ -50,6 +52,7 @@ class SelectSingle(Select):
attrs = {'class': "select_single"}
return super(SelectSingle, self).render(name, value, attrs)
class SelectMultiple(Select):
def render(self, name, value, attrs=None):
if attrs:
@ -58,6 +61,7 @@ class SelectMultiple(Select):
attrs = {'class': "select_multiple"}
return super(SelectMultiple, self).render(name, value, attrs)
class SelectDateTime(DateTimeInput):
def render(self, name, value, attrs=None):
if attrs:
@ -66,6 +70,7 @@ class SelectDateTime(DateTimeInput):
attrs = {'class': "select_datetime"}
return super(SelectDateTime, self).render(name, value, attrs)
class SelectDate(DateInput):
def render(self, name, value, attrs=None):
if attrs:
@ -74,6 +79,7 @@ class SelectDate(DateInput):
attrs = {'class': "select_date"}
return super(SelectDate, self).render(name, value, attrs)
class MarkdownInput(Textarea):
def render(self, name, value, attrs=None):
output = '<p><a href="%(syntax_url)s">%(help_text)s</a></p>'\
@ -84,6 +90,7 @@ class MarkdownInput(Textarea):
}
return output
class SelectFile(TextInput):
def render(self, name, value, attrs=None):
if attrs:
@ -98,6 +105,7 @@ class SelectFile(TextInput):
output += '<span name="' + name + '" class="choose_file_button">' + ugettext("Choose file") + '</span>'
return output
class SelectUser(TextInput):
def render(self, name, value, attrs=None):
if attrs:
@ -114,6 +122,7 @@ class SelectUser(TextInput):
# Forms
class LoginForm(AuthenticationForm):
def __init__(self, *arg, **kwargs):
if 'data' in kwargs.keys():
@ -128,14 +137,17 @@ class LoginForm(AuthenticationForm):
else:
user = User.objects.filter(username=data['username']).first()
data['username'] = user.username
except: pass
except:
pass
kwargs['data'] = data
super(LoginForm, self).__init__(*arg, **kwargs)
self.fields['username'].label = _("Username, email, or account number")
class RegisteringForm(UserCreationForm):
error_css_class = 'error'
required_css_class = 'required'
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
@ -148,9 +160,6 @@ class RegisteringForm(UserCreationForm):
user.save()
return user
from core.utils import resize_image
from io import BytesIO
from PIL import Image
class UserProfileForm(forms.ModelForm):
"""
@ -223,9 +232,11 @@ class UserProfileForm(forms.ModelForm):
{'file_name': f, 'msg': _("Bad image format, only jpeg, png, and gif are accepted")})
self._post_clean()
class UserPropForm(forms.ModelForm):
error_css_class = 'error'
required_css_class = 'required'
class Meta:
model = User
fields = ['groups']
@ -236,13 +247,16 @@ class UserPropForm(forms.ModelForm):
'groups': CheckboxSelectMultiple,
}
class UserGodfathersForm(forms.Form):
type = forms.ChoiceField(choices=[('godfather', _("Godfather")), ('godchild', _("Godchild"))], label=_("Add"))
user = AutoCompleteSelectField('users', required=True, label=_("Select user"), help_text=None)
class PagePropForm(forms.ModelForm):
error_css_class = 'error'
required_css_class = 'required'
class Meta:
model = Page
fields = ['parent', 'name', 'owner_group', 'edit_groups', 'view_groups', ]
@ -255,4 +269,3 @@ class PagePropForm(forms.ModelForm):
super(PagePropForm, self).__init__(*arg, **kwargs)
self.fields['edit_groups'].required = False
self.fields['view_groups'].required = False

View File

@ -29,6 +29,7 @@ from django.core.urlresolvers import reverse_lazy
from core.models import RealGroup
from core.views import CanEditMixin
class GroupListView(CanEditMixin, ListView):
"""
Displays the group list
@ -36,17 +37,20 @@ class GroupListView(CanEditMixin, ListView):
model = RealGroup
template_name = "core/group_list.jinja"
class GroupEditView(CanEditMixin, UpdateView):
model = RealGroup
pk_url_kwarg = "group_id"
template_name = "core/group_edit.jinja"
fields = ['name', 'description']
class GroupCreateView(CanEditMixin, CreateView):
model = RealGroup
template_name = "core/group_edit.jinja"
fields = ['name', 'description']
class GroupDeleteView(CanEditMixin, DeleteView):
model = RealGroup
pk_url_kwarg = "group_id"

View File

@ -23,23 +23,22 @@
#
# This file contains all the views that concern the page model
from django.shortcuts import render, redirect, get_object_or_404
from django.core.urlresolvers import reverse_lazy
from django.views.generic import ListView, DetailView
from django.views.generic.edit import UpdateView, CreateView, DeleteView
from django.contrib.auth.decorators import login_required, permission_required
from django.utils.decorators import method_decorator
from django.forms.models import modelform_factory
from django.forms import CheckboxSelectMultiple, modelform_factory
from django.forms import CheckboxSelectMultiple
from core.models import Page, PageRev, LockError
from core.views.forms import PagePropForm, MarkdownInput
from core.views.forms import MarkdownInput
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
class PageListView(CanViewMixin, ListView):
model = Page
template_name = 'core/page_list.jinja'
class PageView(CanViewMixin, DetailView):
model = Page
template_name = 'core/page_detail.jinja'
@ -54,6 +53,7 @@ class PageView(CanViewMixin, DetailView):
context['new_page'] = self.kwargs['page_name']
return context
class PageHistView(CanViewMixin, DetailView):
model = Page
template_name = 'core/page_hist.jinja'
@ -62,6 +62,7 @@ class PageHistView(CanViewMixin, DetailView):
self.page = Page.get_page_by_full_name(self.kwargs['page_name'])
return self.page
class PageRevView(CanViewMixin, DetailView):
model = Page
template_name = 'core/page_detail.jinja'
@ -84,6 +85,7 @@ class PageRevView(CanViewMixin, DetailView):
context['new_page'] = self.kwargs['page_name']
return context
class PageCreateView(CanCreateMixin, CreateView):
model = Page
form_class = modelform_factory(Page,
@ -115,6 +117,7 @@ class PageCreateView(CanCreateMixin, CreateView):
ret = super(PageCreateView, self).form_valid(form)
return ret
class PagePropView(CanEditPropMixin, UpdateView):
model = Page
form_class = modelform_factory(Page,
@ -145,6 +148,7 @@ class PagePropView(CanEditPropMixin, UpdateView):
raise e
return self.page
class PageEditView(CanEditMixin, UpdateView):
model = PageRev
form_class = modelform_factory(model=PageRev, fields=['title', 'content', ], widgets={'content': MarkdownInput})

View File

@ -22,17 +22,13 @@
#
#
from django.shortcuts import render, redirect, get_object_or_404
from django.db import models
from django.shortcuts import render, redirect
from django.http import JsonResponse
from django.core import serializers
from django.db.models import Q
from django.contrib.auth.decorators import login_required
from django.views.generic import ListView, TemplateView
import os
import json
from itertools import chain
from haystack.query import SearchQuerySet
@ -40,9 +36,11 @@ from core.models import User, Notification
from core.utils import doku_to_markdown, bbcode_to_markdown
from club.models import Club
def index(request, context=None):
return render(request, "core/index.jinja")
class NotificationList(ListView):
model = Notification
template_name = "core/notification_list.jinja"
@ -52,6 +50,7 @@ class NotificationList(ListView):
self.request.user.notifications.update(viewed=True)
return self.request.user.notifications.order_by('-id')[:20]
def notification(request, notif_id):
notif = Notification.objects.filter(id=notif_id).first()
if notif:
@ -60,10 +59,12 @@ def notification(request, notif_id):
return redirect(notif.url)
return redirect("/")
def search_user(query, as_json=False):
res = SearchQuerySet().models(User).filter(text=query).filter_or(text__contains=query)[:20]
return [r.object for r in res]
def search_club(query, as_json=False):
clubs = []
if query:
@ -75,6 +76,7 @@ def search_club(query, as_json=False):
clubs = list(clubs)
return clubs
@login_required
def search_view(request):
result = {
@ -83,6 +85,7 @@ def search_view(request):
}
return render(request, "core/search.jinja", context={'result': result})
@login_required
def search_user_json(request):
result = {
@ -90,6 +93,7 @@ def search_user_json(request):
}
return JsonResponse(result)
@login_required
def search_json(request):
result = {
@ -98,6 +102,7 @@ def search_json(request):
}
return JsonResponse(result)
class ToMarkdownView(TemplateView):
template_name = "core/to_markdown.jinja"
@ -119,4 +124,3 @@ class ToMarkdownView(TemplateView):
kwargs['text'] = ""
kwargs['text_md'] = ""
return kwargs

View File

@ -24,30 +24,29 @@
# This file contains all the views that concern the user model
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import logout as auth_logout, views
from django.contrib.auth import views
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist, ValidationError
from django.core.exceptions import PermissionDenied, ValidationError
from django.http import Http404
from django.views.generic.edit import UpdateView
from django.views.generic import ListView, DetailView, TemplateView, DeleteView
from django.views.generic import ListView, DetailView, TemplateView
from django.forms.models import modelform_factory
from django.forms import CheckboxSelectMultiple
from django.template.response import TemplateResponse
from django.conf import settings
from django.views.generic.dates import YearMixin, MonthMixin
from django.utils import timezone
from datetime import timedelta, datetime, date
from datetime import timedelta, date
import logging
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin, QuickNotifMixin
from core.views.forms import RegisteringForm, UserPropForm, UserProfileForm, LoginForm, UserGodfathersForm
from core.views.forms import RegisteringForm, UserProfileForm, LoginForm, UserGodfathersForm
from core.models import User, SithFile, Preferences
from club.models import Club
from subscription.models import Subscription
from trombi.views import UserTrombiForm
def login(request):
"""
The login view
@ -56,24 +55,28 @@ def login(request):
"""
return views.login(request, template_name="core/login.jinja", authentication_form=LoginForm)
def logout(request):
"""
The logout view
"""
return views.logout_then_login(request)
def password_change(request):
"""
Allows a user to change its password
"""
return views.password_change(request, template_name="core/password_change.jinja", post_change_redirect=reverse("core:password_change_done"))
def password_change_done(request):
"""
Allows a user to change its password
"""
return views.password_change_done(request, template_name="core/password_change_done.jinja")
def password_root_change(request, user_id):
"""
Allows a root user to change someone's password
@ -92,6 +95,7 @@ def password_root_change(request, user_id):
form = views.SetPasswordForm(user=user)
return TemplateResponse(request, "core/password_change.jinja", {'form': form, 'target': user})
def password_reset(request):
"""
Allows someone to enter an email adresse for resetting password
@ -102,12 +106,14 @@ def password_reset(request):
post_reset_redirect="core:password_reset_done",
)
def password_reset_done(request):
"""
Confirm that the reset email has been sent
"""
return views.password_reset_done(request, template_name="core/password_reset_done.jinja")
def password_reset_confirm(request, uidb64=None, token=None):
"""
Provide a reset password formular
@ -117,6 +123,7 @@ def password_reset_confirm(request, uidb64=None, token=None):
template_name="core/password_reset_confirm.jinja",
)
def password_reset_complete(request):
"""
Confirm the password has sucessfully been reset
@ -125,6 +132,7 @@ def password_reset_complete(request):
template_name="core/password_reset_complete.jinja",
)
def register(request):
context = {}
if request.method == 'POST':
@ -143,6 +151,7 @@ def register(request):
context['form'] = form.as_p()
return render(request, "core/register.jinja", context)
class UserTabsMixin(TabedViewMixin):
def get_tabs_title(self):
return self.object.get_display_name()
@ -208,9 +217,11 @@ class UserTabsMixin(TabedViewMixin):
'slug': 'account',
'name': _("Account") + " (%s €)" % self.object.customer.amount,
})
except: pass
except:
pass
return tab_list
class UserView(UserTabsMixin, CanViewMixin, DetailView):
"""
Display a user's profile
@ -236,6 +247,7 @@ def DeleteUserGodfathers(request, user_id, godfather_id, is_father):
raise PermissionDenied
return redirect('core:user_godfathers', user_id=user_id)
class UserPicturesView(UserTabsMixin, CanViewMixin, DetailView):
"""
Display a user's pictures
@ -246,6 +258,7 @@ class UserPicturesView(UserTabsMixin, CanViewMixin, DetailView):
template_name = "core/user_pictures.jinja"
current_tab = 'pictures'
class UserGodfathersView(UserTabsMixin, CanViewMixin, DetailView):
"""
Display a user's godfathers
@ -277,6 +290,7 @@ class UserGodfathersView(UserTabsMixin, CanViewMixin, DetailView):
kwargs['form'] = UserGodfathersForm()
return kwargs
class UserStatsView(UserTabsMixin, CanViewMixin, DetailView):
"""
Display a user's stats
@ -303,7 +317,7 @@ class UserStatsView(UserTabsMixin, CanViewMixin, DetailView):
def get_context_data(self, **kwargs):
kwargs = super(UserStatsView, self).get_context_data(**kwargs)
from counter.models import Counter, Product, Selling
from counter.models import Counter
from django.db.models import Sum
foyer = Counter.objects.filter(name="Foyer").first()
mde = Counter.objects.filter(name="MDE").first()
@ -323,6 +337,7 @@ class UserStatsView(UserTabsMixin, CanViewMixin, DetailView):
product_sum=Sum('quantity')).exclude(product_sum=None).order_by('-product_sum').all()[:10]
return kwargs
class UserMiniView(CanViewMixin, DetailView):
"""
Display a user's profile
@ -332,6 +347,7 @@ class UserMiniView(CanViewMixin, DetailView):
context_object_name = "profile"
template_name = "core/user_mini.jinja"
class UserListView(ListView, CanEditPropMixin):
"""
Displays the user list
@ -339,6 +355,7 @@ class UserListView(ListView, CanEditPropMixin):
model = User
template_name = "core/user_list.jinja"
class UserUploadProfilePictView(CanEditMixin, DetailView):
"""
Handle the upload of the profile picture taken with webcam in navigator
@ -367,6 +384,7 @@ class UserUploadProfilePictView(CanEditMixin, DetailView):
self.object.save()
return redirect("core:user_edit", user_id=self.object.id)
class UserUpdateProfileView(UserTabsMixin, CanEditMixin, UpdateView):
"""
Edit a user's profile
@ -412,6 +430,7 @@ class UserUpdateProfileView(UserTabsMixin, CanEditMixin, UpdateView):
kwargs['form'] = self.form
return kwargs
class UserClubView(UserTabsMixin, CanViewMixin, DetailView):
"""
Display the user's club(s)
@ -422,6 +441,7 @@ class UserClubView(UserTabsMixin, CanViewMixin, DetailView):
template_name = "core/user_clubs.jinja"
current_tab = "clubs"
class UserPreferencesView(UserTabsMixin, CanEditMixin, UpdateView):
"""
Edit a user's preferences
@ -453,6 +473,7 @@ class UserPreferencesView(UserTabsMixin, CanEditMixin, UpdateView):
kwargs['trombi_form'] = UserTrombiForm()
return kwargs
class UserUpdateGroupView(UserTabsMixin, CanEditPropMixin, UpdateView):
"""
Edit a user's groups
@ -465,6 +486,7 @@ class UserUpdateGroupView(UserTabsMixin, CanEditPropMixin, UpdateView):
context_object_name = "profile"
current_tab = "groups"
class UserToolsView(QuickNotifMixin, UserTabsMixin, TemplateView):
"""
Displays the logged user's tools
@ -481,6 +503,7 @@ class UserToolsView(QuickNotifMixin, UserTabsMixin, TemplateView):
kwargs['object'] = self.request.user
return kwargs
class UserAccountBase(UserTabsMixin, DetailView):
"""
Base class for UserAccount
@ -498,6 +521,7 @@ class UserAccountBase(UserTabsMixin, DetailView):
return res
raise PermissionDenied
class UserAccountView(UserAccountBase):
"""
Display a user's account
@ -551,6 +575,7 @@ class UserAccountView(UserAccountBase):
print(repr(e))
return kwargs
class UserAccountDetailView(UserAccountBase, YearMixin, MonthMixin):
"""
Display a user's account for month
@ -568,4 +593,3 @@ class UserAccountDetailView(UserAccountBase, YearMixin, MonthMixin):
pass
kwargs['tab'] = "account"
return kwargs