class GoogleFormIndex(Page): title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') description_en = RichTextField( verbose_name=_('English description'), blank=True, ) description_sv = RichTextField( verbose_name=_('Swedish description'), blank=True, ) description = TranslatedField('description_en', 'description_sv') # Editor panels configuration content_panels = Page.content_panels + [ FieldPanel('title_sv', classname="full title"), FieldPanel('description_en'), FieldPanel('description_sv'), ] # Sub-page type rules subpage_types = ['google.GoogleFormPage'] def get_context(self, request, **kwargs): context = super(GoogleFormIndex, self).get_context(request, **kwargs) # Add extra variables and return the updated context context['google_forms'] = GoogleFormPage.objects.child_of(self).live()\ .order_by('-deadline') return context
class HomePage(Page): # ---- General Page information ------ title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') body_en = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [('news', LatestNewsBlock())], blank=True, ) body_sv = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [('news', LatestNewsBlock())], blank=True, ) body = TranslatedField('body_en', 'body_sv') banner_panels = [InlinePanel('banners', label=_('Banner'))] content_panels_en = Page.content_panels + [ StreamFieldPanel('body_en'), ] content_panels_sv = [ FieldPanel('title_sv', classname="full title"), StreamFieldPanel('body_sv'), ] edit_handler = TabbedInterface([ ObjectList(banner_panels, heading=_('Banners')), ObjectList(content_panels_en, heading=_('English')), ObjectList(content_panels_sv, heading=_('Swedish')), ObjectList(Page.promote_panels, heading=_('Promote')), ObjectList(Page.settings_panels, heading=_('Settings')), ])
class HomePage(Page): # ---- General Page information ------ title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') show_searchbar = models.BooleanField(default=True) add_whitespace_bottom = models.BooleanField(default=True) body_en = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [ ('news', LatestNewsBlock()), ('html', RawHTMLBlock(group="Basic")), ], blank=True, ) body_sv = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [ ('news', LatestNewsBlock()), ('html', RawHTMLBlock(group="Basic")), ], blank=True, ) body = TranslatedField('body_en', 'body_sv') banner_panels = [InlinePanel('banners', label=_('Banner'))] content_panels_en = Page.content_panels + [ StreamFieldPanel('body_en'), ] content_panels_sv = [ FieldPanel('title_sv', classname="full title"), StreamFieldPanel('body_sv'), ] custom_settings_panel = Page.settings_panels + [ MultiFieldPanel( [ FieldPanel('show_searchbar'), FieldPanel('add_whitespace_bottom') ], heading='Banner settings', classname='utn-extra-margin' ) ] edit_handler = TabbedInterface([ ObjectList(banner_panels, heading=_('Banners')), ObjectList(content_panels_en, heading=_('English')), ObjectList(content_panels_sv, heading=_('Swedish')), ObjectList(Page.promote_panels, heading=_('Promote')), ObjectList(custom_settings_panel, heading=_('Settings')), ]) api_fields = [ APIField('title_sv'), APIField('body_en'), APIField('body_sv'), ]
class StudyProgram(models.Model): """This class describes a university study program""" class Meta: verbose_name_plural = _('Study Programs') DEGREE_CHOICES = ( ('bachelor', _('Bachelor\'s Degree')), ('master', _('Master\'s Degree')), ('engineer', _('Engineer\'s Degree')), ) name_en = models.CharField( max_length=255, verbose_name=_('English program name'), help_text=_('Enter the name of the study program'), null=False, blank=False, ) name_sv = models.CharField( max_length=255, verbose_name=_('Swedish program name'), help_text=_('Enter the name of the study program'), null=False, blank=False, ) name = TranslatedField('name_en', 'name_sv') abbreviation_en = models.CharField( max_length=130, verbose_name=_('English program abbreviation'), help_text=_('Enter the abbreviation for the study program'), null=True, blank=True, ) abbreviation_sv = models.CharField( max_length=130, verbose_name=_('Swedish program abbreviation'), help_text=_('Enter the abbreviation for the study program'), null=True, blank=True, ) abbreviation = TranslatedField('name_en', 'name_sv') degree = models.CharField( max_length=20, choices=DEGREE_CHOICES, verbose_name=_('Degree type'), blank=False, null=False, ) def __str__(self) -> str: return '%s in %s' % (self.get_degree_display(), self.name)
class NewsPage(Page): title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') body_en = RichTextField() body_sv = RichTextField() body = TranslatedField('body_en', 'body_sv') created = models.DateTimeField( verbose_name=_('Created at'), auto_now_add=True, ) modified = models.DateTimeField( verbose_name=_('Modified at'), auto_now=True, ) feed_image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+' ) # Search index configuration search_fields = Page.search_fields + [ index.SearchField('title_sv'), index.SearchField('body_en'), index.SearchField('body_sv'), index.FilterField('created'), index.FilterField('modified'), ] # Editor panels configuration content_panels = Page.content_panels + [ FieldPanel('body_en', classname="full"), ] content_panels_sv = [ FieldPanel('title_sv', classname="full title"), FieldPanel('body_sv', classname="full"), ] promote_panels = [ ImageChooserPanel('feed_image') ] + Page.promote_panels edit_handler = TabbedInterface([ ObjectList(content_panels, heading=_('English')), ObjectList(content_panels_sv, heading=_('Swedish')), ObjectList(promote_panels, heading=_('Promote')), ObjectList(Page.settings_panels, heading=_('Settings')), ]) # Parent page / sub-page type rules parent_page_types = ['news.NewsIndexPage'] subpage_types = []
class GoogleFormPage(Page): title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') # TODO: Limit to one form! form_en = StreamField([('google_form', GoogleFormBlock())]) form_sv = StreamField([('google_form', GoogleFormBlock())]) form = TranslatedField('form_en', 'form_sv') deadline = models.DateField(verbose_name=_('Form deadline')) results_en = StreamField( WAGTAIL_STATIC_BLOCKTYPES, blank=True, ) results_sv = StreamField( WAGTAIL_STATIC_BLOCKTYPES, blank=True, ) results = TranslatedField('results_en', 'results_sv') @property def is_past_due(self) -> bool: return date.today() > self.deadline # Editor panels configuration content_panels = Page.content_panels + [ FieldPanel('title_sv', classname="full title"), FieldPanel('deadline'), StreamFieldPanel('form_en'), StreamFieldPanel('form_sv'), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading=_('Common')), ObjectList([StreamFieldPanel('results_en')], heading=_('English')), ObjectList([StreamFieldPanel('results_sv')], heading=_('Swedish')), ObjectList( Page.promote_panels + Page.settings_panels, heading=_('Settings') ), ]) # Search index configuration search_fields = Page.search_fields + [ index.SearchField('title_sv'), index.FilterField('results_en'), index.FilterField('results_sv'), index.FilterField('deadline'), ] # Parent page / subpage type rules parent_page_types = ['google.GoogleFormIndex'] subpage_types = []
class WebPage(Page): # ---- General Page information ------ title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') body_en = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [ ('google_calendar', GoogleCalendarBlock()), ('google_drive', GoogleDriveBlock()), ('google_form', GoogleFormBlock()), ('news', LatestNewsBlock()), ('html', RawHTMLBlock(group="Basic")), ('eventbrite', EventbriteBlock()), ], blank=True, ) body_sv = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [('google_calendar', GoogleCalendarBlock()), ('google_drive', GoogleDriveBlock()), ('google_form', GoogleFormBlock()), ('news', LatestNewsBlock()), ('html', RawHTMLBlock(group="Basic")), ('eventbrite', EventbriteBlock())], blank=True, ) body = TranslatedField('body_en', 'body_sv') content_panels_en = Page.content_panels + [ StreamFieldPanel('body_en'), ] content_panels_sv = [ FieldPanel('title_sv', classname="full title"), StreamFieldPanel('body_sv'), ] edit_handler = TabbedInterface([ ObjectList(content_panels_en, heading=_('English')), ObjectList(content_panels_sv, heading=_('Swedish')), ObjectList(Page.promote_panels, heading=_('Promote')), ObjectList(Page.settings_panels, heading=_('Settings')), ]) api_fields = [ APIField('title_sv'), APIField('body_en'), APIField('body_sv'), ]
class RecruitmentPage(RoutablePageMixin, Page): # ---- General Page information ------ title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') # ------ Team selection ------ included_teams = ParentalManyToManyField( 'Team', verbose_name=_('Included teams'), help_text=_('Choose teams to include on the page'), related_name='include_on_page', blank=True, ) excluded_teams = ParentalManyToManyField( 'Team', verbose_name=_('Excluded teams'), help_text=_('Choose teams to exclude from the page'), related_name='exclude_on_page', blank=True, ) # ------ Routing ------ @route(r'^$') def open_positions(self, request): """View redirect for the currently open positions""" from involvement import views return views.open_positions(request, self.get_context(request)) @route(r'^my_applications/$') def my_applications(self, request): """View redirect for the applications by user""" from involvement import views return views.my_applications(request, self.get_context(request)) @route(r'^position/(\d+)/$', name='position') def position(self, request, position=None): """ View redirect for a specific position. """ from involvement import views return views.position(request, self.get_context(request), self, position) # ------ Administrator settings ------ content_panels = Page.content_panels + [ FieldPanel('title_sv'), FieldPanel('included_teams', widget=forms.CheckboxSelectMultiple), FieldPanel('excluded_teams', widget=forms.CheckboxSelectMultiple), ] # Don't allow any sub pages subpage_types = []
class GoogleCalendarPage(Page): title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') content_panels = Page.content_panels + [ FieldPanel('title_sv', classname="full title"), ] subpage_types = [] def get_context(self, request, **kwargs): context = super(GoogleCalendarPage, self) \ .get_context(request, **kwargs) id = request.GET.get('id') context['id'] = quote(id, safe="%/:=~+!$,;'@()*[]") context['date'] = request.GET.get('date', None) return context
class NewsIndexPage(Page): title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') # Editor panels configuration content_panels = Page.content_panels + [ FieldPanel('title_sv', classname="full title"), ] # Sub-page type rules subpage_types = ['news.NewsPage'] def get_context(self, request, **kwargs): context = super(NewsIndexPage, self).get_context(request, **kwargs) context['news_items'] = NewsPage.objects.child_of(self).live() \ .order_by('-created') return context
class StudyProgram(models.Model): """This class describes a university study program""" class Meta: verbose_name = _('study program') verbose_name_plural = _('study programs') DEGREE_CHOICES = ( ('bsc', _('Bachelor of Science')), ('msc', _('Master of Science')), ('be', _('Bachelor of Engineering')), ('msceng', _('Master of Science in Engineering')), ) name_en = models.CharField( max_length=255, verbose_name=_('English program name'), help_text=_('Enter the name of the study program'), blank=False, ) name_sv = models.CharField( max_length=255, verbose_name=_('Swedish program name'), help_text=_('Enter the name of the study program'), blank=False, ) name = TranslatedField('name_en', 'name_sv') degree = models.CharField( max_length=20, choices=DEGREE_CHOICES, verbose_name=_('Degree type'), blank=True, ) def __str__(self) -> str: if self.degree: return _('%(degree_type)s in %(study_program)s') % { 'degree_type': self.get_degree_display(), 'study_program': self.name, } else: return self.name.__str__()
class Section(models.Model): """This class represent a study section""" class Meta: verbose_name = _('section') verbose_name_plural = _('sections') name_en = models.CharField( max_length=255, verbose_name=_('English section name'), help_text=_('Enter the name of the section'), blank=False, ) name_sv = models.CharField( max_length=255, verbose_name=_('Swedish section name'), help_text=_('Enter the name of the section'), blank=False, ) name = TranslatedField('name_en', 'name_sv') abbreviation = models.CharField( max_length=130, verbose_name=_('Section abbreviation'), help_text=_('Enter the abbreviation for the section'), blank=True, ) studies = ManyToManyField( 'StudyProgram', related_name='sections', blank=True, ) def __str__(self) -> str: if self.abbreviation: return '%s - %s' % (self.abbreviation, self.name) else: return self.name.__str__()
def translated_title(self): from utils.translation import LANGUAGE as language translated_field = TranslatedField('title', 'title_en', 'title_pt') return translated_field.get(self, language)
class RecruitmentPage(RoutablePageMixin, Page): # ---- General Page information ------ title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') # ------ Team selection ------ included_teams = ParentalManyToManyField( 'Team', verbose_name=_('Included teams'), help_text=_('Choose teams to include on the page. This overrules' 'excluded teams'), related_name='include_on_page', blank=True, ) excluded_teams = ParentalManyToManyField( 'Team', verbose_name=_('Excluded teams'), help_text=_('Choose teams to exclude from the page'), related_name='exclude_on_page', blank=True, ) # ------ Methods ------ def get_context(self, request, *args, **kwargs): context = super(RecruitmentPage, self).get_context(request, *args, **kwargs) context['positions'] = Position.objects.all() if self.included_teams.all(): context['positions'] = context['positions'].filter( role__team__in=self.included_teams.all()) elif self.excluded_teams.all(): context['positions'] = context['positions'].exclude( role__team__in=self.excluded_teams.all()) return context # ------ Routing ------ @route(r'^$') def open_positions(self, request): """View redirect for the currently open positions""" from involvement import views return views.open_positions(request, self.get_context(request)) @route(r'^my_applications/$') def my_applications(self, request): """View redirect for the applications by user""" from involvement import views return views.my_applications(request, self.get_context(request)) @route(r'^my_mandates/$') def my_mandates(self, request): """View redirect for the mandate histories by user""" from involvement import views return views.my_mandates(request, self.get_context(request)) @route(r'^position/(\d+)/$') def position(self, request, position=None): """ View redirect for a specific position. """ from involvement import views return views.view_position(request, self.get_context(request), self, position) # ------ Administrator settings ------ content_panels = Page.content_panels + [ FieldPanel('title_sv'), FieldPanel('included_teams', widget=forms.CheckboxSelectMultiple), FieldPanel('excluded_teams', widget=forms.CheckboxSelectMultiple), ] # Don't allow any sub pages subpage_types = []
class ContactCard(models.Model): role = models.OneToOneField( 'Role', blank=True, null=True, on_delete=models.SET_NULL, related_name='contact_cards', ) picture = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') description_en = RichTextField( verbose_name=_('English Description'), blank=True, ) description_sv = RichTextField( verbose_name=_('Swedish Description'), blank=True, ) description = TranslatedField('description_en', 'description_sv') name = models.CharField( max_length=100, verbose_name=_('Name'), help_text=_('Overrides account name of position holder of the selected' ' role.'), blank=True, ) role_text_en = models.CharField( max_length=100, verbose_name=_('English Role Name'), help_text=_('Overrides role name from the selected role.'), blank=True, ) role_text_sv = models.CharField( max_length=100, verbose_name=_('Swedish Role Name'), help_text=_('Overrides role name from the selected role.'), blank=True, ) role_text = TranslatedField('role_text_en', 'role_text_sv') email = models.EmailField( verbose_name=_('Email address'), help_text=_('Overrides account email address of position holder of the' ' selected role.'), blank=True, ) def __str__(self) -> str: if self.role: return self.role.__str__() else: return '%(name)s - %(role)s' % { 'name': self.name, 'role': self.role_text } panels = [ FieldPanel('role'), ImageChooserPanel('picture'), FieldPanel('description_en'), FieldPanel('description_sv'), FieldPanel('name'), FieldPanel('role_text_en'), FieldPanel('role_text_sv'), FieldPanel('email'), ]
class Function(models.Model): """ This class represents a function held by a member within UTN or its committees """ class Meta: verbose_name_plural = _('Functions') default_permissions = () team = models.ForeignKey( Team, related_name='functions', on_delete=models.PROTECT, null=True, blank=True, ) official = models.BooleanField( verbose_name=_('Official'), help_text=_('Function has official access in the website'), default=False, ) # Display position in selection? archived = models.BooleanField( verbose_name=_('Archived'), help_text=_('Hide the position from menus'), default=False, ) # ---- General Information ------ name_en = models.CharField( max_length=255, verbose_name=_('English function name'), help_text=_('Enter the name of the function'), blank=False, ) name_sv = models.CharField( max_length=255, verbose_name=_('Swedish function name'), help_text=_('Enter the name of the function'), blank=False, ) name = TranslatedField('name_en', 'name_sv') description_en = models.TextField( verbose_name=_('English function description'), help_text=_('Enter a description of the function'), blank=True, ) description_sv = models.TextField( verbose_name=_('Swedish function description'), help_text=_('Enter a description of the function'), blank=True, ) description = TranslatedField('description_en', 'description_sv') def __str__(self) -> str: return _('{} in {}').format(self.name, self.team) # ------ Administrator settings ------ panels = [ MultiFieldPanel([ FieldPanel('team'), FieldRowPanel([ FieldPanel('name_en'), FieldPanel('name_sv'), ]), FieldPanel('description_en'), FieldPanel('description_sv'), FieldRowPanel([ FieldPanel('archived'), FieldPanel('official'), ]), ]) ]
class ContactPage(Page): # ---- General Page information ------ title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') contact_point = StreamField( [('person', ContactCardBlock())], ) other_contacts = StreamField( [('contact', blocks.StructBlock([ ('person', ContactCardBlock()), ('english_groups', blocks.CharBlock( help_text=_('Comma separated list of English group names.'), required=False, )), ('swedish_groups', blocks.CharBlock( help_text=_('Comma separated list of Swedish group names.'), required=False, )), ], icon='user'))], ) map_location = models.CharField( max_length=255, verbose_name=_('Map Location'), help_text=_('Enter comma separated coordinates'), blank=True, ) location_description = RichTextField( verbose_name=_('Location Description'), help_text=_('Enter the text to show on the map'), blank=True, ) def get_context(self, request, *args, **kwargs): contacts = {} for contact in self.other_contacts: if request.LANGUAGE_CODE == 'sv': groups = contact.value.get('swedish_groups', '') else: groups = contact.value.get('english_groups', '') groups = groups.split(',') for group in groups: group = group.strip() l = contacts.get(group, []) l.append(contact.value['person']) contacts[group] = l context = super(ContactPage, self).get_context( request, *args, **kwargs ) context['contacts'] = contacts return context content_panels = Page.content_panels + [ FieldPanel('title_sv', classname="full title"), FieldPanel('map_location'), FieldPanel('location_description'), StreamFieldPanel('contact_point'), StreamFieldPanel('other_contacts'), ]
class Banner(Orderable): page = ParentalKey( HomePage, related_name='banners', on_delete=models.CASCADE, blank=False, ) image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+' ) title_en = models.CharField( max_length=255, verbose_name=_('English banner title'), help_text=_('Enter the title to be shown on the banner.'), blank=True, ) title_sv = models.CharField( max_length=255, verbose_name=_('Swedish banner title'), help_text=_('Enter the title to be shown on the banner.'), blank=True, ) title = TranslatedField('title_en', 'title_sv') text_en = models.TextField( verbose_name=_('English banner text'), help_text=_('Enter a text to be shown on the banner.'), blank=True, ) text_sv = models.TextField( verbose_name=_('Swedish banner text'), help_text=_('Enter a text to be shown on the banner.'), blank=True, ) text = TranslatedField('text_en', 'text_sv') link = models.URLField( verbose_name=_('Button URL'), blank=True, ) button_en = models.TextField( verbose_name=_('English button text'), help_text=_('Enter the text to be displayed on the button.'), blank=True, ) button_sv = models.TextField( verbose_name=_('Swedish button text'), help_text=_('Enter the text to be displayed on the button.'), blank=True, ) button = TranslatedField('button_en', 'button_sv') # ------ Administrator settings ------ panels = [MultiFieldPanel([ ImageChooserPanel('image'), FieldRowPanel([ FieldPanel('title_en'), FieldPanel('title_sv'), ]), FieldPanel('text_en'), FieldPanel('text_sv'), FieldPanel('link'), FieldRowPanel([ FieldPanel('button_en'), FieldPanel('button_sv'), ]), ])]
class Position(models.Model): """Appointment represents the holding of a function.""" class Meta: verbose_name_plural = _('Positions') default_permissions = () function = models.ForeignKey( Function, related_name='positions', on_delete=models.PROTECT, blank=False, ) commencement = models.DateField( verbose_name=_('Commencement of recruitment'), default=date.today, ) deadline = models.DateField(verbose_name=_('Recruitment deadline')) # ---- Appointment Information ------ appointments = models.IntegerField( verbose_name=_('Number of appointments'), help_text=_('Enter the number of concurrent appointments to the ' 'position'), default=1, ) term_from = models.DateField(verbose_name=_('Date of appointment')) term_to = models.DateField(verbose_name=_('End date of appointment')) comment_en = models.TextField( verbose_name=_('English extra comments'), help_text=_('Enter extra comments specific to the position this ' 'year.'), blank=True, ) comment_sv = models.TextField( verbose_name=_('Swedish extra comments'), help_text=_('Enter extra comments specific to the position this ' 'year.'), blank=True, ) comment = TranslatedField('comment_en', 'comment_sv') def __str__(self) -> str: return "{} {}".format(self.function.name, self.term_from.year) @property def is_past_due(self): return date.today() > self.deadline # ------ Administrator settings ------ panels = [ MultiFieldPanel([ FieldRowPanel([ FieldPanel('function'), FieldPanel('appointments'), ]), FieldRowPanel([ FieldPanel('term_from'), FieldPanel('term_to'), ]), FieldRowPanel([ FieldPanel('commencement'), FieldPanel('deadline'), ]), FieldPanel('comment_en'), FieldPanel('comment_sv'), ]) ]
class Role(models.Model): """ This class represents a role within a team or UTN """ class Meta: verbose_name = _('Role') verbose_name_plural = _('Roles') default_permissions = () TYPE_CHOICES = ( ('admin', _('Admin')), ('fum', _('FUM')), ('board', _('Board')), ('presidium', _('Presidium')), ('group_leader', _('Group Leader')), ('engaged', _('Engaged')), ) role_type = models.CharField( max_length=20, choices=TYPE_CHOICES, verbose_name=_('Role type'), blank=False, null=False, ) group = models.ForeignKey( Group, related_name='roles', on_delete=models.PROTECT, ) teams = models.ManyToManyField( 'Team', related_name='roles', blank=True, ) # Display position in selection? archived = models.BooleanField( verbose_name=_('Archived'), help_text=_('Hide the role from menus'), default=False, ) # ---- General Information ------ name_en = models.CharField( max_length=255, verbose_name=_('English role name'), help_text=_('Enter the name of the role'), blank=False, ) name_sv = models.CharField( max_length=255, verbose_name=_('Swedish role name'), help_text=_('Enter the name of the role'), blank=False, ) name = TranslatedField('name_en', 'name_sv') description_en = models.TextField( verbose_name=_('English role description'), help_text=_('Enter a description of the role'), blank=True, ) description_sv = models.TextField( verbose_name=_('Swedish role description'), help_text=_('Enter a description of the role'), blank=True, ) description = TranslatedField('description_en', 'description_sv') election_email = models.EmailField( verbose_name=_('Election contact email address'), help_text=_('The email address to contact for more information ' 'regarding the role.'), blank=False, default='*****@*****.**', ) contact_email = models.EmailField( verbose_name=_('Contact email address'), help_text=_('The email address for the current position holder'), blank=True, ) phone_number = models.CharField( max_length=20, verbose_name=_('Phone number'), help_text=_('Enter a phone number to contact this role.'), validators=[ validators.RegexValidator( regex=r'^\+?\d+$', message=_('Please enter a valid phone number'), ) ], blank=True, ) @property def contact_phone_number(self): """ Returns: If self.phone_number is blank. Will return first occurence of a current position holder for this role if any, self.phone_number otherwise """ if not self.phone_number: current_holder = self.members.first() if current_holder is not None: return current_holder.phone_number return self.phone_number @property def members(self): member_model = apps.get_model(settings.AUTH_USER_MODEL) return member_model.objects.filter( application__position__role=self, application__status='appointed', application__position__term_from__lte=date.today(), application__position__term_to__gte=date.today(), ) @staticmethod def editable_role_types(user): if user.is_anonymous: return [] if is_admin(user): return [ 'admin', 'fum', 'board', 'presidium', 'group_leader', 'engaged' ] elif is_fum(user): return ['board'] elif is_board(user): return ['presidium'] elif is_presidium(user): return ['group_leader', 'engaged'] elif is_group_leader(user): return ['engaged'] return [] @staticmethod def edit_applicant_role_types(user): if user.is_anonymous: return [] if is_admin(user): return [ 'admin', 'fum', 'board', 'presidium', 'group_leader', 'engaged' ] elif is_fum(user): return ['board', 'presidium'] elif is_board(user): return ['presidium'] elif is_presidium(user): return ['group_leader', 'engaged'] elif is_group_leader(user): return ['engaged'] return [] @staticmethod def edit_role_types_of(user, pk=False): if user.is_anonymous: return [] if pk else Role.objects.none() role_type_filter = Role.editable_role_types(user) roles = Role.objects.filter(role_type__in=role_type_filter, teams__in=user.teams) if pk: return roles.values_list('pk', flat=True) else: return roles @staticmethod def edit_applicant_permission_of(user, pk=False): if user.is_anonymous: return [] if pk else Role.objects.none() role_type_filter = Role.edit_applicant_role_types(user) roles = Role.objects.filter(role_type__in=role_type_filter, teams__in=user.teams) if pk: return roles.values_list('pk', flat=True) else: return roles @property def team_names(self): return ', '.join([str(i) for i in self.teams.all()]) @property def member_names(self): return ', '.join([str(i) for i in self.members]) @property def team_logo(self): if self.teams.count(): return self.teams.first().logo return None @property def current_positions(self): return self.positions.filter( term_from__lte=date.today(), term_to__gte=date.today(), ) @property def old_positions(self): return self.positions.filter(term_to__lte=date.today()) def __str__(self) -> str: if self.teams: return _('%(role)s in %(teams)s') % { 'role': self.name, 'teams': self.team_names, } else: return self.name # ------ Administrator settings ------ panels = [ MultiFieldPanel([ FieldRowPanel([ FieldPanel('name_en'), FieldPanel('name_sv'), ]), FieldPanel('group'), FieldPanel('election_email'), FieldPanel('contact_email'), FieldPanel('phone_number'), FieldPanel('description_en'), FieldPanel('description_sv'), FieldRowPanel([ FieldPanel('archived'), ]), FieldPanel('role_type'), FieldPanel('teams', widget=CheckboxSelectMultiple), ]) ]
def translated_intro(self): from utils.translation import LANGUAGE as language translated_field = TranslatedField('intro_es', 'intro_en', 'intro_pt') return translated_field.get(self, language)
class Team(models.Model): """This class represents a working group within UTN""" class Meta: verbose_name_plural = _('Teams') default_permissions = () permissions = (('admin', _('Can administrate the recruitment process')), ) group = models.OneToOneField( Group, on_delete=models.PROTECT, ) # ---- General Information ------ name_en = models.CharField( max_length=255, verbose_name=_('English team name'), help_text=_('Enter the name of the team'), blank=False, ) name_sv = models.CharField( max_length=255, verbose_name=_('Swedish team name'), help_text=_('Enter the name of the team'), blank=False, ) name = TranslatedField('name_en', 'name_sv') logo = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') description_en = models.TextField( verbose_name=_('English team description'), help_text=_('Enter a description of the team'), blank=True, ) description_sv = models.TextField( verbose_name=_('Swedish team description'), help_text=_('Enter a description of the team'), blank=True, ) description = TranslatedField('description_en', 'description_sv') # ---- Contact Information ------ leader_en = models.CharField( max_length=255, verbose_name=_('English team leader position name'), help_text=_('Enter the name of position of the team leader'), blank=True, ) leader_sv = models.CharField( max_length=255, verbose_name=_('Swedish team leader position name'), help_text=_('Enter the name of position of the team leader'), blank=True, ) leader = TranslatedField('leader_en', 'leader_sv') email = models.EmailField( verbose_name=_('Contact e-mail address'), blank=True, ) def __str__(self) -> str: return '{}'.format(self.name) # ------ Administrator settings ------ panels = [ MultiFieldPanel([ FieldRowPanel([ FieldPanel('name_en'), FieldPanel('name_sv'), ]), FieldPanel('group'), ImageChooserPanel('logo'), FieldRowPanel([ FieldPanel('leader_en'), FieldPanel('leader_sv'), ]), FieldPanel('email'), FieldPanel('description_en'), FieldPanel('description_sv'), ]) ]
class Position(models.Model): """Position represents the execution of a role within UTN""" class Meta: verbose_name = _('Position') verbose_name_plural = _('Positions') default_permissions = () ordering = ['role'] role = models.ForeignKey( 'Role', related_name='positions', on_delete=models.PROTECT, blank=False, ) recruitment_start = models.DateField( verbose_name=_('Start of recruitment'), default=date.today, ) recruitment_end = models.DateField(verbose_name=_('Recruitment deadline')) # ---- Appointment Information ------ appointments = models.IntegerField( verbose_name=_('Number of appointments'), help_text=_('Enter the number of concurrent appointments to the ' 'position'), default=1, ) term_from = models.DateField(verbose_name=_('Date of appointment')) term_to = models.DateField(verbose_name=_('End date of appointment')) comment_en = models.TextField( verbose_name=_('English extra comments'), help_text=_('Enter extra comments specific to the position this ' 'year.'), blank=True, ) comment_sv = models.TextField( verbose_name=_('Swedish extra comments'), help_text=_('Enter extra comments specific to the position this ' 'year.'), blank=True, ) comment = TranslatedField('comment_en', 'comment_sv') def __str__(self) -> str: if self.term_from.year != self.term_to.year: return "%s %s-%s" \ % (self.role.name, self.term_from.year, self.term_to.year) else: return "%s %s" % (self.role.name, self.term_from.year) @property def appointed_applications(self): Application = apps.get_model('involvement', 'Application') return Application.objects.filter( status='appointed', position=self, ) @property def is_past_due(self): return date.today() > self.recruitment_end def current_action(self) -> str: if self.is_past_due: applications = self.applications.exclude(status='draft') if applications.all().filter(status='submitted').exists(): return 'approve' elif applications.all().filter(status='appointed') \ .count() >= self.appointments: return 'done' else: return 'appoint' else: return 'recruit' # ------ Administrator settings ------ panels = [ MultiFieldPanel([ FieldRowPanel([ FieldPanel('role'), FieldPanel('appointments'), ]), FieldRowPanel([ FieldPanel('term_from'), FieldPanel('term_to'), ]), FieldRowPanel([ FieldPanel('recruitment_start'), FieldPanel('recruitment_end'), ]), FieldPanel('comment_en'), FieldPanel('comment_sv'), ]) ]
class Role(models.Model): """ This class represents a role within a team or UTN """ class Meta: verbose_name = _('Role') verbose_name_plural = _('Roles') default_permissions = () team = models.ForeignKey( 'Team', related_name='roles', on_delete=models.PROTECT, null=True, blank=True, ) official = models.BooleanField( verbose_name=_('Official'), help_text=_('This is an official role'), default=False, ) # Display position in selection? archived = models.BooleanField( verbose_name=_('Archived'), help_text=_('Hide the role from menus'), default=False, ) # ---- General Information ------ name_en = models.CharField( max_length=255, verbose_name=_('English role name'), help_text=_('Enter the name of the role'), blank=False, ) name_sv = models.CharField( max_length=255, verbose_name=_('Swedish role name'), help_text=_('Enter the name of the role'), blank=False, ) name = TranslatedField('name_en', 'name_sv') description_en = models.TextField( verbose_name=_('English role description'), help_text=_('Enter a description of the role'), blank=True, ) description_sv = models.TextField( verbose_name=_('Swedish role description'), help_text=_('Enter a description of the role'), blank=True, ) description = TranslatedField('description_en', 'description_sv') election_email = models.EmailField( verbose_name=_('Election contact email address'), help_text=_('The email address to contact for more information ' 'regarding the role.'), blank=False, default='*****@*****.**', ) def in_role(self): member_model = apps.get_model(settings.AUTH_USER_MODEL) return member_model.objects.filter( application__position__role=self, application__status='appointed', application__position__term_from__lte=date.today(), application__position__term_to__gte=date.today(), ) def __str__(self) -> str: if self.team: return _('%(role)s in %(team)s') % { 'role': self.name, 'team': self.team, } else: return self.name # ------ Administrator settings ------ panels = [ MultiFieldPanel([ FieldPanel('team'), FieldRowPanel([ FieldPanel('name_en'), FieldPanel('name_sv'), ]), FieldPanel('election_email'), FieldPanel('description_en'), FieldPanel('description_sv'), FieldRowPanel([ FieldPanel('archived'), FieldPanel('official'), ]), ]) ]
class Team(models.Model): """This class represents a working group within UTN""" class Meta: verbose_name = _('Team') verbose_name_plural = _('Teams') default_permissions = () # ---- General Information ------ name_en = models.CharField( max_length=255, verbose_name=_('English team name'), help_text=_('Enter the name of the team'), blank=False, ) name_sv = models.CharField( max_length=255, verbose_name=_('Swedish team name'), help_text=_('Enter the name of the team'), blank=False, ) name = TranslatedField('name_en', 'name_sv') logo = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') description_en = models.TextField( verbose_name=_('English team description'), help_text=_('Enter a description of the team'), blank=True, ) description_sv = models.TextField( verbose_name=_('Swedish team description'), help_text=_('Enter a description of the team'), blank=True, ) description = TranslatedField('description_en', 'description_sv') def __str__(self) -> str: return '{}'.format(self.name) @property def members(self): return get_user_model().objects.filter( application__position__role__teams__pk=self.pk, application__position__term_from__lte=date.today(), application__position__term_to__gte=date.today(), application__status='appointed', ) @property def manual_members(self): members = self.members.values('pk') return get_user_model().objects.filter(groups=self.group).exclude( pk__in=members) # ------ Administrator settings ------ panels = [ MultiFieldPanel([ FieldRowPanel([ FieldPanel('name_en'), FieldPanel('name_sv'), ]), ImageChooserPanel('logo'), FieldPanel('description_en'), FieldPanel('description_sv'), ]) ]
class FormPage(AbstractEmailForm): title_sv = models.CharField(max_length=255) translated_title = TranslatedField('title', 'title_sv') intro_en = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [ ('contact_card', ContactCardBlock()), ], verbose_name=_('English Introduction'), blank=True, ) intro_sv = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [ ('contact_card', ContactCardBlock()), ], verbose_name=_('Swedish Introduction'), blank=True, ) intro = TranslatedField('intro_en', 'intro_sv') thank_you_text_en = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [ ('contact_card', ContactCardBlock()), ], verbose_name=_('English Thank You Text'), blank=True, ) thank_you_text_sv = StreamField( WAGTAIL_STATIC_BLOCKTYPES + [ ('contact_card', ContactCardBlock()), ], verbose_name=_('Swedish Thank You Text'), blank=True, ) thank_you_text = TranslatedField('thank_you_text_en', 'thank_you_text_sv') form_title_en = models.CharField(verbose_name=_('English Form Title'), max_length=255, blank=True) form_title_sv = models.CharField( verbose_name=_('Swedish Form Title'), max_length=255, blank=True, ) form_title = TranslatedField('form_title_en', 'form_title_sv') general_panels = [ InlinePanel('form_fields', label="Form fields"), MultiFieldPanel([ FieldRowPanel([ FieldPanel('from_address', classname="col6"), FieldPanel('to_address', classname="col6"), ]), FieldPanel('subject'), ], "Email"), ] content_panels_en = AbstractEmailForm.content_panels + [ StreamFieldPanel('intro_en'), FieldPanel('form_title_en', classname="full title"), StreamFieldPanel('thank_you_text_en'), ] content_panels_sv = [ FieldPanel('title_sv', classname="full title"), StreamFieldPanel('intro_sv'), FieldPanel('form_title_sv', classname="full title"), StreamFieldPanel('thank_you_text_sv'), ] edit_handler = TabbedInterface([ ObjectList(general_panels, heading=_('General')), ObjectList(content_panels_en, heading=_('English')), ObjectList(content_panels_sv, heading=_('Swedish')), ObjectList(Page.promote_panels, heading=_('Promote')), ObjectList(Page.settings_panels, heading=_('Settings')), ])
def translated_content(self): from utils.translation import LANGUAGE as language translated_field = TranslatedField('content_es', 'content_en', 'content_pt') return translated_field.get(self, language)