def url_picker_context(site): """Return template context needed for the URL picker utility""" articles = Article.objects.filter( # Article has not reached its unpublish date Q(unpub_date__gt=date.today()) | Q(unpub_date__isnull=True), published=True, pub_date__lt=datetime.now(), site=site, ).prefetch_related( 'versions', # Note that content prefetching is necessary because we will later # extract the title content 'versions__rows', 'versions__rows__columns', 'versions__rows__columns__contents', ).order_by( '-pub_date', ) return {'url_picker': { 'pages': Page.objects.filter(site=site).order_by('title'), 'articles': articles, 'foreninger': Forening.get_all_sorted(), 'site': site, }}
def index(request): context = { 'admin_user_search_char_length': settings.ADMIN_USER_SEARCH_CHAR_LENGTH, 'turleder_roles': Turleder.TURLEDER_CHOICES, 'instruktor_roles': Instruktor.ROLE_CHOICES, 'all_foreninger': Forening.get_all_sorted(), } return render(request, 'central/admin/turledere/index.html', context)
def show(request, user_id): try: other_user = User.objects.filter( id=user_id, ).prefetch_related( 'turleder_active_foreninger', ).get() except User.DoesNotExist: messages.warning(request, 'no_such_user') return redirect('admin:users.index') # Admins can assign user/admin, users can assign users assignable_admin = [a for a in request.user.all_foreninger() if a.role == 'admin'] assignable_user = [a for a in request.user.all_foreninger() if a.role == 'user'] # Don't let users assign new permissions for those that already have user status # Use ForeningRole for other_user, because we can't set permissions for foreninger that are # based on parent foreninger (to remove access to a child, you have to remove admin-permission # to the parent) other_user_foreninger = Forening.objects.filter(users=other_user) assignable_user = [a for a in assignable_user if a not in other_user_foreninger] assignable_foreninger = assignable_admin + assignable_user # Only admins can revoke forening relation revokable_foreninger = [a for a in assignable_admin if a in other_user_foreninger] today = date.today() # We can't just add 365*5 timedelta days because that doesn't account for leap years, # this does. try: five_years_from_now = date(year=(today.year + 5), month=today.month, day=today.day) except ValueError: # This will only occur when today is February 29th during a leap year (right?) five_years_from_now = date(year=(today.year + 5), month=today.month, day=(today.day - 1)) context = { 'other_user': other_user, 'revokable_foreninger': Forening.sort(revokable_foreninger), 'assignable_foreninger': Forening.sort(assignable_foreninger), 'all_foreninger': Forening.get_all_sorted(), 'turleder_roles': Turleder.TURLEDER_CHOICES, 'five_years_from_now': five_years_from_now, } return render(request, 'central/admin/users/show/index.html', context)
def process_request(self, request): if 'active_forening' in request.session: try: request.active_forening = Forening.get_cached_forening( id=request.session['active_forening'], ) except Forening.DoesNotExist: # It might have been removed, remove it and let the user choose # a new one del request.session['active_forening']
def index(request): query = request.GET.copy() # Default organizers: If visiting a local site, default to the owner of the current site (except for DNT central) if not request.GET.get("organizers", "") and request.site.forening.id != Forening.DNT_CENTRAL_ID: query["organizers"] = "%s:%s" % ("forening", request.site.forening.id) # Default minimum duration is always 1 query["min_duration"] = query.get("min_duration", "1") filter, aktivitet_dates = filter_aktivitet_dates(query) aktivitet_dates_pagenav = paginate_aktivitet_dates(filter, aktivitet_dates) # Usually, the 'sentral' type is sorted first, but in this case we want it last all_foreninger = Forening.get_all_sorted() sentral = all_foreninger[0] if not sentral["code"] == "sentral": # We made an incorrect assumption, log it but try to continue rendering instead of raising an error logger.error( "Assumed first group of forening to be type 'sentral', was really '%s'" % sentral["code"], extra={"request": request, "all_foreninger": all_foreninger}, ) # Remove and append the sentral group to the end all_foreninger.remove(sentral) all_foreninger.append(sentral) # Look up DNT cabins with serving cabins = sorted( Sted.list( params={ "tags": "Hytte", "betjeningsgrad": "Betjent", "privat": {"hytteeier": "DNT"}, "status": "Offentlig", "tilbyder": "DNT", } ), key=lambda s: s["navn"], ) context = { "aktivitet_dates": aktivitet_dates_pagenav, "difficulties": Aktivitet.DIFFICULTY_CHOICES, "categories": Aktivitet.CATEGORY_CHOICES, "category_types": Aktivitet.CATEGORY_TYPES_LIST, "audiences": Aktivitet.AUDIENCE_CHOICES, "omrader": sorted(Område.list(params={"status": "Offentlig", "tilbyder": "DNT"}), key=lambda o: o["navn"]), "cabins": cabins, "all_foreninger": all_foreninger, "filter": filter, } return render(request, "common/aktiviteter/index.html", context)
def url_picker_context(active_site): article_versions = Version.objects.select_related('variant', 'variant__article').filter( variant__article__isnull=False, variant__segment__isnull=True, variant__article__published=True, active=True, variant__article__pub_date__lt=datetime.now(), variant__article__site=active_site, ).order_by('-variant__article__pub_date') return {'url_picker': { 'pages': Page.on(active_site).order_by('title'), 'article_versions': article_versions, 'foreninger': Forening.get_all_sorted(), }}
def admin_context(self, site): # Look up DNT cabins with serving cabins = sorted(Sted.list(params={ 'tags': 'Hytte', 'betjeningsgrad': 'Betjent', 'grupper': '', 'privat': {'hytteeier': 'DNT'}, 'status': 'Offentlig', 'tilbyder': 'DNT', }), key=lambda s: s['navn']) return { 'all_foreninger_sorted': Forening.get_all_sorted(), 'audiences': Aktivitet.AUDIENCE_CHOICES, 'categories': Aktivitet.CATEGORY_CHOICES, 'category_types': [{ 'category': [c[1] for c in Aktivitet.CATEGORY_CHOICES if c[0] == category['category']][0], 'types': category['types'] } for category in Aktivitet.CATEGORY_TYPES_LIST], 'cabins': cabins, }
def create(request, forening_id): current_forening = Forening.objects.get(id=forening_id) if current_forening not in request.user.all_foreninger(): raise PermissionDenied # The parent choices are tricky to define in the forms API, so do it here. # Note that we're intentionally letting users choose parents among only those they have permission to. all_sorted = request.user.all_foreninger_sorted() parents_choices = { 'forening': all_sorted['forening'], 'turlag': all_sorted['turlag'], } # If the parent of the current forening isn't in the user's permissions, we still need to include that one as an # available parent so that they're able to make changes. if current_forening.type != 'sentral': for current_parent in current_forening.get_main_foreninger(): if current_parent not in parents_choices['forening'] and current_parent not in parents_choices['turlag']: parents_choices[current_parent.type].append(current_parent) form = CreateForeningForm(request.user, initial={ 'zipcode': '', }) context = { 'current_forening': current_forening, 'parents_choices': parents_choices, 'admin_user_search_char_length': settings.ADMIN_USER_SEARCH_CHAR_LENGTH, 'form': form, } # Give URLPicker the homepage site for the current forening. If they don't have one, just use the central site relevant_site = current_forening.get_homepage_site() or Site.get_central() context.update(url_picker_context(relevant_site)) if request.method == 'GET': return render(request, 'central/admin/foreninger/create.html', context) elif request.method == 'POST': form = CreateForeningForm(request.user, request.POST) if form.is_valid(): forening = Forening() forening.name = form.cleaned_data['name'] forening.type = form.cleaned_data['type'] if forening.type == 'turgruppe': forening.group_type = form.cleaned_data['group_type'] else: forening.group_type = '' forening.save() # Set M2M-fields after the initial db-save forening.parents = form.cleaned_data['parents'] # Ensure the Turbasen object is re-saved with applicable M2M-relations forening.save_turbasen_object() # Add the current user as admin on the new forening role = ForeningRole( user=request.user, forening=forening, role='admin', ) role.save() # FIXME: We can't delete the permission cache for all users, so some may find that they can't edit # the new forening even though they should be able, until the cache (which is currently 24h) expires. cache.delete('user.%s.all_foreninger' % request.user.id) messages.info(request, 'forening_create_success') request.session['active_forening'] = forening.id cache.delete('foreninger.all.sorted_by_name') cache.delete('foreninger.all.sorted_by_type') cache.delete('foreninger.rendered_select') cache.delete('forening.%s' % forening.id) cache.delete('forening.main_foreninger.%s' % forening.id) return redirect('admin:foreninger.edit', forening.id) else: context.update({'form': form}) return render(request, 'central/admin/foreninger/create.html', context) else: return redirect('admin:foreninger.create', current_forening.id)
def renew_membership(request): if request.method != 'POST': return redirect('user:account') if 'stripeToken' not in request.POST: return redirect('user:account') description = "Fornying av medlemskap" if date.today() < membership_year_start()['public_date']: applicable_year = membership_year_start()['public_date'].year else: applicable_year = membership_year_start()['public_date'].year + 1 metadata = { 'Periode': 'Medlemsåret %s' % applicable_year, } if not request.user.has_family(): # Single member, pay their own invoice amount = request.user.payment.status['amount_due'] metadata['Medlemskap'] = request.user.membership_type()['name'] metadata['Medlem'] = '%s (medlemsnr: %s)' % (request.user.get_full_name(), request.user.memberid) request.user.clear_cache() elif request.user.family.relation == 'family': # Family membership, pay the invoice of the parent amount = request.user.payment.status['amount_due'] metadata['Medlemskap'] = 'Familiemedlemskap' metadata['Familie hovedmedlem'] = '%s (medlemsnr: %s)' % ( request.user.family.parent.get_full_name(), request.user.family.parent.memberid, ) metadata['Alle familiemedlemmer'] = ', '.join([ '%s (medlemsnr: %s)' % (u.get_full_name(), u.memberid) for u in request.user.family.all_members() ]) request.user.family.clear_cache() elif request.user.family.relation == 'household': # Household membership, each member has their own invoice. amount = request.user.family.payment_amount_due() metadata['Medlemskap'] = 'Husstandsmedlemskap' metadata['Medlemmer'] = ', '.join([ '%s (medlemsnr: %s, %s, %s)' % ( u.get_full_name(), u.memberid, u.membership_type()['name'], currency(u.payment.status['amount_due']), ) for u in request.user.family.payment_members() ]) request.user.family.clear_cache() charge = Charge.new_charge( Forening.get_cached_forening(id=Forening.DNT_CENTRAL_ID).payment_auth()['stripe_user_id'], request.user, request.POST['stripeToken'], amount, description, metadata, ) try: if not charge.was_success(): # Unsuccessful payment. Store the error message and display it on the account page request.session['membership.%s.payment_failure' % request.user.memberid] = { 'error_display': charge.get_error_code_display(), 'error_message': charge.error_message, } else: # Payment was succesful; save it to Focus if not request.user.has_family() or request.user.family.relation == 'family': request.user.payment.save_pending_payment(charge.charge_id, amount) else: for household_member in request.user.family.payment_members(): household_member.payment.save_pending_payment( charge.charge_id, household_member.payment.status['amount_due'], ) except: # Problem during pending payment registration - likely connection issue with Focus. # - Since the payment isn't stored in Focus, the user will not get the confirmation, so add an error message # explaining the situation. # - Manual followup is required by memberservice, so send email to memberservice with required information # - Log an error to be able to trace events, in case it's ever needed messages.error(request, 'payment_registration_failure') logger.error( "Feil ved lagring av medlemskapsfornyelse i Focus", exc_info=sys.exc_info(), extra={ 'request': request, 'amount': amount, 'metadata': metadata, 'charge': charge, }, ) try: context = { 'amount': amount, 'metadata': metadata, 'charge': charge, } message = render_to_string('common/focus/payment_registration_failure.txt', context, request=request) send_mail( "Fornying av medlemskap kunne ikke lagres i Focus", message, settings.DEFAULT_FROM_EMAIL, [settings.MEMBERSERVICE_EMAIL], ) except (SMTPException, SSLError, UnicodeEncodeError): # Jesus. Error upon error. Log it, hopefully devs will be able to follow up. logger.error( "Kunne ikke sende varselsepost til medlemsservice, beskjed må gis manuelt", extra={ 'request': request, 'message': message, 'amount': amount, 'metadata': metadata, 'charge': charge, }, ) finally: return redirect('%s#forny-medlemskap' % reverse('user:account'))
def edit(request, aktivitet): if request.method == 'GET': aktivitet = Aktivitet.objects.prefetch_related('municipalities', 'counties').get(id=aktivitet) context = { 'aktivitet': aktivitet, 'difficulties': Aktivitet.DIFFICULTY_CHOICES, 'audiences': AktivitetAudience.AUDIENCE_CHOICES, 'categories': Aktivitet.CATEGORY_CHOICES, 'all_foreninger': Forening.get_all_sorted(), 'cabins': Cabin.objects.order_by('name'), 'admin_user_search_char_length': settings.ADMIN_USER_SEARCH_CHAR_LENGTH, 'counties': County.typical_objects().order_by('name'), 'municipalities': Municipality.objects.order_by('name'), 'omrader': sorted(Omrade.lookup(), key=lambda o: o.navn), 'now': datetime.now() } return render(request, 'common/admin/aktiviteter/edit/edit.html', context) elif request.method == 'POST': errors = False aktivitet = Aktivitet.objects.get(id=aktivitet) if aktivitet.is_imported(): # Should only be possible by circumventing client-side restrictions return redirect('admin.aktiviteter.views.edit', aktivitet.id) if 'code' in request.POST: aktivitet.code = request.POST['code'] if 'title' in request.POST: aktivitet.title = request.POST['title'] if 'description' in request.POST: aktivitet.description = request.POST['description'] if 'difficulty' in request.POST: aktivitet.difficulty = request.POST['difficulty'] if 'audiences' in request.POST: aktivitet.audiences = [ AktivitetAudience.objects.get(name=audience) for audience in request.POST.getlist('audiences') ] if 'category' in request.POST: aktivitet.category = request.POST['category'] if 'category_type' in request.POST: aktivitet.category_type = request.POST['category_type'] if 'publish' in request.POST: aktivitet.published = request.POST.get('publish') == 'publish' if 'getting_there' in request.POST: aktivitet.getting_there = request.POST['getting_there'] if 'omrader' in request.POST: aktivitet.omrader = request.POST.getlist('omrader') if 'ntb_id' not in request.POST or request.POST['ntb_id'] == '': aktivitet.turforslag = None else: aktivitet.turforslag = request.POST['ntb_id'] if aktivitet.published: # If published, set the extra relevant fields (otherwise ignore them) aktivitet.private = request.POST['private'] == 'private' try: aktivitet.pub_date = datetime.strptime(request.POST['pub_date'], "%d.%m.%Y").date() except ValueError: errors = True messages.error(request, 'invalid_date_format') forening_type, forening_id = request.POST['forening'].split(':') if forening_type == 'forening': forening = Forening.objects.get(id=forening_id) if not forening in request.user.children_foreninger(): raise PermissionDenied aktivitet.forening = forening elif forening_type == 'cabin': aktivitet.forening_cabin = Cabin.objects.get(id=forening_id) else: raise PermissionDenied if 'co_foreninger[]' in request.POST and request.POST['co_foreninger[]'] != '': co_foreninger = [] co_foreninger_cabin = [] for co_forening in request.POST.getlist('co_foreninger[]'): type, id = co_forening.split(':') if type == 'forening': co_foreninger.append(id) elif type == 'cabin': co_foreninger_cabin.append(id) else: raise PermissionDenied aktivitet.co_foreninger = co_foreninger aktivitet.co_foreninger_cabin = co_foreninger_cabin else: aktivitet.co_foreninger = [] aktivitet.co_foreninger_cabin = [] if 'latlng' in request.POST: latlng = request.POST['latlng'].split(',') if len(latlng) == 2: aktivitet.start_point = Point(float(latlng[0]), float(latlng[1])) aktivitet.save() aktivitet.counties = request.POST.getlist('counties') aktivitet.municipalities = request.POST.getlist('municipalities') aktivitet.category_tags.clear() if 'category_tags' in request.POST and request.POST['category_tags'] != '': for tag in request.POST.getlist('category_tags'): obj, created = Tag.objects.get_or_create(name=tag) aktivitet.category_tags.add(obj) aktivitet.images.all().delete() for i, image in parse_html_array(request.POST, 'images').items(): AktivitetImage( aktivitet=aktivitet, url=image['url'], text=image['description'], photographer=image['photographer'], order=i ).save() dates = parse_html_array(request.POST, 'dates').items() # Remove the date objects that were explicitly deleted (checks and verifications are done # client-side). Verify that those that would be implicitly deleted (by not being POSTed for # editing) match those explicitly POSTed. date_ids = [int(d['id']) for k, d in dates if d['id'] != ''] implicit_del = set([date.id for date in aktivitet.dates.all() if date.id not in date_ids]) if len(implicit_del) > 0: # Better to raise an exception and not delete anything. The user will be confused and # lose edits, but we'll get a report and hopefully be able to fix this, if it ever # happens. raise Exception("Implicit delete of AktivitetDate is strictly forbidden!") for i, date in dates: if date['id'] != '': # @TODO Check if this can be exploited. Can you hijack another trip's date by # setting an arbitrary ID in the date['id'] field? model = AktivitetDate.objects.get(id=date['id']) else: model = AktivitetDate(aktivitet=aktivitet) # @TODO for existing dates; if model.start_date > now; dissalow editing. # Explicit delete of dates if date['status'] == 'delete': if date['id'] != '': if model.participant_count() > 0: raise Exception("Date with participants can not be deleted!") model.delete() continue try: if not date['start_time']: date['start_time'] = '08:00' if not date['end_time']: date['end_time'] = '16:00' # @TODO check start_time > now model.start_date = datetime.strptime( "%s %s" % (date['start_date'], date['start_time']), "%d.%m.%Y %H:%M" ) # @TODO check end_time > start_time model.end_date = datetime.strptime( "%s %s" % (date['end_date'], date['end_time']), "%d.%m.%Y %H:%M" ) # @TODO check start_date > meeting_time if date['start_date'] and date['meeting_time']: model.meeting_time = datetime.strptime( "%s %s" % (date['start_date'], date['meeting_time']), "%d.%m.%Y %H:%M" ) if not date['signup_method'] or date['signup_method'] == 'none': # To the next maintainer. This block indicates that a date does not allow # signup. However, keep in mind that this might be an existing date with # participants. Hence, do not set model.participant to None event though it # might be tempting! model.signup_enabled = False model.signup_start = None model.signup_deadline = None model.cancel_deadline = None elif date['signup_method'] == 'normal' or date['signup_method'] == 'simple': model.signup_enabled = True if date.get('max_participants_limited'): model.max_participants = date['max_participants'] else: model.max_participants = None if date.get('no_signup_start') == '1': model.signup_start = None else: model.signup_start = datetime.strptime( date['signup_start'], "%d.%m.%Y", ).date() if 'no_signup_deadline' in date and date['no_signup_deadline'] == '1': model.signup_deadline = None elif 'signup_deadline' in date and date['signup_deadline'] != '': model.signup_deadline = datetime.strptime( date['signup_deadline'], "%d.%m.%Y", ).date() if 'no_cancel_deadline' in date and date['no_cancel_deadline'] == '1': model.cancel_deadline = None elif 'cancel_deadline' in date and date['cancel_deadline'] != '': model.cancel_deadline = datetime.strptime( date['cancel_deadline'], "%d.%m.%Y" ).date() else: raise Exception("Unrecognized POST value for signup_method field") except ValueError: errors = True messages.error(request, 'invalid_date_format') return redirect('admin.aktiviteter.views.edit', aktivitet.id) # Note that simple signup is currently disabled and due to be removed model.signup_simple_allowed = False model.meeting_place = date['meeting_place'] model.contact_type = date['contact_type'] model.contact_custom_name = date['contact_custom_name'] model.contact_custom_phone = date['contact_custom_phone'] model.contact_custom_email = date['contact_custom_email'] model.should_have_turleder = date.get('should_have_turleder') == '1' model.save() if date.get('should_have_turleder') == '1': # We need to specify the key for this particular field because the parse_html_array # function does not properly parse multidimensional arrays. key = 'dates[%s][turleder][]' % i if key in request.POST and request.POST[key] != '': model.turledere = request.POST.getlist(key) else: model.turledere = [] if not errors: messages.info(request, 'save_success') if json.loads(request.POST['preview']): return redirect('admin.aktiviteter.views.preview', aktivitet.id) else: return redirect('admin.aktiviteter.views.edit', aktivitet.id)
def index(request): filter_ = DEFAULT_FILTER.copy() filter_.update(request.GET.dict()) # Default organizers: If visiting a local site, default to the owner of the current site (except for DNT central) if not filter_['organizers'] and request.site.forening.id != Forening.DNT_CENTRAL_ID: filter_['organizers'] = '%s:%s' % ('forening', request.site.forening.id) # Interestingly, the paginator will perform a COUNT query to count the # total number of objects, regardless of whether it is used in the # template. Therefore, even if we get a cache hit for the listing template # fragment, it will perform the query unnecessarily. So explicitly check # if the current filter is cached or not, and if so, skip the pagination. cache_key = make_template_fragment_key( 'aktivitet_listing', [filter_hash(filter_)], ) if cache.get(cache_key) is not None: aktivitet_dates_pagenav = None else: filter_, aktivitet_dates = filter_aktivitet_dates(filter_) aktivitet_dates_pagenav = paginate_aktivitet_dates(filter_, aktivitet_dates) # Usually, the 'sentral' type is sorted first, but in this case we want it last all_foreninger = Forening.get_all_sorted() sentral = all_foreninger[0] if not sentral['code'] == 'sentral': # We made an incorrect assumption, log it but try to continue rendering instead of raising an error logger.error( "Assumed first group of forening to be type 'sentral', was really '%s'" % sentral['code'], extra={ 'request': request, 'all_foreninger': all_foreninger, } ) # Remove and append the sentral group to the end all_foreninger.remove(sentral) all_foreninger.append(sentral) # Look up DNT cabins with serving cabins = sorted(Sted.list(params={ 'tags': 'Hytte', 'betjeningsgrad': 'Betjent', 'privat': {'hytteeier': 'DNT'}, 'status': 'Offentlig', 'tilbyder': 'DNT', }), key=lambda s: s['navn']) # Set url query parameters for pagination links query_string = get_filter_query_string(request.GET.dict()) context = { 'aktivitet_dates': aktivitet_dates_pagenav, 'difficulties': Aktivitet.DIFFICULTY_CHOICES, 'categories': Aktivitet.CATEGORY_CHOICES, 'category_types': Aktivitet.CATEGORY_TYPES_LIST, 'audiences': Aktivitet.AUDIENCE_CHOICES, 'omrader': sorted(Område.list(params={'status': 'Offentlig', 'tilbyder': 'DNT'}), key=lambda o: o['navn']), 'cabins': cabins, 'all_foreninger': all_foreninger, 'query_string': query_string, 'filter': filter_, 'filter_hash': filter_hash(filter_), } return render(request, 'common/aktiviteter/index.html', context)
def children_foreninger_sorted(self): return Forening.sort(self.children_foreninger())
def all_foreninger_sorted_with_type_data(self): return Forening.sort_with_type_data(self.all_foreninger())
def create(request, forening_id): current_forening = Forening.objects.get(id=forening_id) if current_forening not in request.user.all_foreninger(): raise PermissionDenied # The parent choices are tricky to define in the forms API, so do it here. # Note that we're intentionally letting users choose parents among only # those they have permission to. all_sorted = request.user.all_foreninger_sorted() parents_choices = { 'forening': all_sorted['forening'], 'turlag': all_sorted['turlag'], } # If the parent of the current forening isn't in the user's permissions, we # still need to include that one as an available parent so that they're # able to make changes. if current_forening.type != 'sentral': for current_parent in current_forening.get_main_foreninger(): if (current_parent not in parents_choices['forening'] and current_parent not in parents_choices['turlag']): parents_choices[current_parent.type].append(current_parent) form = CreateForeningForm(request.user, initial={ 'zipcode': '', }) context = { 'current_forening': current_forening, 'parents_choices': parents_choices, 'admin_user_search_char_length': settings.ADMIN_USER_SEARCH_CHAR_LENGTH, 'form': form, } # Give URLPicker the homepage site for the current forening. If they don't # have one, just use the central site relevant_site = current_forening.get_homepage_site() or Site.get_central() context.update(url_picker_context(relevant_site)) if request.method == 'GET': return render(request, 'central/admin/foreninger/create.html', context) elif request.method == 'POST': form = CreateForeningForm(request.user, request.POST) if form.is_valid(): forening = Forening() forening.name = form.cleaned_data['name'] forening.type = form.cleaned_data['type'] if forening.type == 'turgruppe': forening.group_type = form.cleaned_data['group_type'] else: forening.group_type = '' forening.save() # Set M2M-fields after the initial db-save forening.parents = form.cleaned_data['parents'] # Ensure the Turbasen object is re-saved with applicable # M2M-relations forening.save_turbasen_object() # Add the current user as admin on the new forening request.user.add_perm( 'sherpa/association/user', association_id=forening.id, created_by=request.user ) request.user.add_perm( 'sherpa/association/admin', association_id=forening.id, created_by=request.user ) cache.clear() return redirect('admin:foreninger.edit', forening.id) else: context.update({'form': form}) return render( request, 'central/admin/foreninger/create.html', context) else: return redirect('admin:foreninger.create', current_forening.id)
def clean(self): cleaned_data = super().clean() type_ = cleaned_data.get('type') parents = cleaned_data.get('parents') if type_ in ['sentral', 'forening']: # In this case, the UI will have hidden the parents input, but it might still have a value, so # force it to empty. The hiding of the field should make this behavior intuitive. cleaned_data['parent'] = [] parents = [] # These types must have a parent, but that can't be enforced on the DB-level for *new* foreninger since parents # are a M2M-relationship (so the child needs to be saved before the parent can be related), so check it here. if type_ in ['turlag', 'turgruppe'] and len(parents) == 0: self.add_error( 'parents', "%s må ha en moderforening!" % ( 'Et turlag' if type_ == 'turlag' else 'En turgruppe', ) ) parents = None # Non DNT admins cannot set type forening/sentral if not self._user.is_admin_in_dnt_central() and type_ in ['sentral', 'forening']: self.add_error( 'type', "Du har ikke tillatelse til å opprette sentrale grupper eller medlemsforeninger. Vennligst ta " \ "kontakt med DNT sentralt.", ) # Validate the new forening type and parents relationship try: forening = Forening() forening.validate_relationships( simulate_type=type_, simulate_parents=parents, ) except ForeningWithItselfAsParent: self.add_error( 'parents', "%s kan ikke være underlagt seg selv." % forening.name ) except SentralForeningWithRelation: self.add_error( 'parents', "En sentral forening kan ikke ha noen koblinger til andre foreningstyper." ) except ForeningWithForeningParent: self.add_error( 'parents', "En forening kan ikke være underlagt en annen forening." ) except TurlagWithTurlagParent: self.add_error( 'parents', "Et turlag kan ikke være underlagt et annet turlag." ) except TurgruppeWithTurgruppeParent: self.add_error( 'parents', "En turgruppe kan ikke være underlagt en annen turgruppe." ) except ForeningWithTurlagParent: self.add_error( 'parents', "Foreninger kan ikke være underlagt turlag/turgrupper." ) except TurlagWithTurgruppeParent: self.add_error( 'parents', "Et turlag kan ikke være underlagt en turgruppe." ) return cleaned_data
def show(request, user_id): try: other_user = User.objects.filter( id=user_id, ).prefetch_related( 'turledere', 'turleder_active_foreninger', ).get() except User.DoesNotExist: messages.warning(request, 'no_such_user') return redirect('admin:users.index') # Admins can assign user/admin, users can assign users assignable_admin = [ a for a in request.user.all_foreninger() if a.role == 'admin' ] assignable_user = [ a for a in request.user.all_foreninger() if a.role == 'user' ] # Don't let users assign new permissions for those that already have user # status. # Use UserPermissionGrant for other_user, because we can't set permissions # for foreninger that are based on parent foreninger (to remove access to # a child, you have to remove admin-permission to the parent) p_name = 'sherpa/association/user' other_user_foreninger = Forening.objects.filter( user_permission_grants__user_permission__name=p_name, user_permission_grants__user=other_user ) assignable_user = [ a for a in assignable_user if a not in other_user_foreninger ] assignable_foreninger = assignable_admin + assignable_user # Only admins can revoke forening relation revokable_foreninger = [ a for a in assignable_admin if a in other_user_foreninger ] today = date.today() # We can't just add 365*5 timedelta days because that doesn't account for # leap years, this does. try: five_years_from_now = date( year=(today.year + 5), month=today.month, day=today.day ) except ValueError: # This will only occur when today is February 29th during a leap year # (right?) five_years_from_now = date( year=(today.year + 5), month=today.month, day=(today.day - 1) ) # Select participant groups where user is signee or participant aktivitet_data = get_aktivitet_list_participant_groups(other_user) # Sort by user / other aktiviteter_user = { 'past': [a for a in aktivitet_data['past'] if a['user_is_signed_up']], 'future': [ a for a in aktivitet_data['future'] if a['user_is_signed_up']], } aktiviteter_other = { 'past': [ a for a in aktivitet_data['past'] if not a['user_is_signed_up']], 'future': [ a for a in aktivitet_data['future'] if not a['user_is_signed_up']], } # Get aktiviteter from montis montis_error = False montis_data = None if other_user.is_member(): montis_data = get_aktivitet_list_from_montis(other_user) montis_error = montis_data.get('montis_error', False) if (len(montis_data['past']) + len(montis_data['future'])) == 0: montis_data = None else: montis_data['past'].sort(key=lambda d: d['start_date']) montis_data['future'].sort(key=lambda d: d['start_date']) aktiviteter_count = ( len(aktivitet_data['past']) + len(aktivitet_data['future'])) if montis_data: aktiviteter_count += ( len(montis_data['past']) + len(montis_data['future'])) # Select dates where user is turleder turleder_dates = other_user.turleder_aktivitet_dates.all() turleder_dates = { 'future': [d for d in turleder_dates if d.start_date >= date.today()], 'past': [d for d in turleder_dates if d.start_date < date.today()], } context = { 'other_user': other_user, 'revokable_foreninger': Forening.sort(revokable_foreninger), 'assignable_foreninger': Forening.sort(assignable_foreninger), 'all_foreninger': Forening.get_all_sorted(), 'turleder_roles': Turleder.TURLEDER_CHOICES, 'five_years_from_now': five_years_from_now, 'aktiviteter_user': aktiviteter_user, 'aktiviteter_other': aktiviteter_other, 'montis_data': montis_data, 'aktiviteter_count': aktiviteter_count, 'turleder_dates': turleder_dates, 'montis_error': montis_error, 'consent_pretty': json.dumps(other_user.consent, indent=2), 'consent': other_user.get_consent_preferences(), 'consent_json': json.dumps(other_user.consent), } if other_user.is_member() and other_user.can_reserve_against_publications(): context.update({ 'enable_publications_toggle': True, 'can_reserve_against_publications': other_user.can_reserve_against_publications(), 'reserved_against_fjellogvidde': other_user.get_reserved_against_fjellogvidde(), 'reserved_against_yearbook': other_user.get_reserved_against_yearbook(), }) return render(request, 'central/admin/users/show/index.html', context)
def clean(self): cleaned_data = super().clean() type_ = cleaned_data.get('type') parents = cleaned_data.get('parents') if type_ in ['sentral', 'forening']: # In this case, the UI will have hidden the parents input, but it might still have a value, so # force it to empty. The hiding of the field should make this behavior intuitive. cleaned_data['parent'] = [] parents = [] # These types must have a parent, but that can't be enforced on the DB-level for *new* foreninger since parents # are a M2M-relationship (so the child needs to be saved before the parent can be related), so check it here. if type_ in ['turlag', 'turgruppe'] and len(parents) == 0: self.add_error( 'parents', "%s må ha en moderforening!" % ( 'Et turlag' if type_ == 'turlag' else 'En turgruppe', ) ) parents = None # The following check should be skipped if this form is actually an # instance of the EditForeningForm subclass if not isinstance(self, EditForeningForm): # Non DNT admins cannot set type forening/sentral. Note that the # edit form should allow non-admins to save objects of this type # as long as it isn't changed. if not self._user.is_admin_in_dnt_central() and type_ in ['sentral', 'forening']: self.add_error( 'type', "Du har ikke tillatelse til å opprette sentrale grupper eller medlemsforeninger. Vennligst ta " \ "kontakt med DNT sentralt.", ) # Validate focus_id focus_id = cleaned_data['focus_id'] if focus_id is not None: others = Forening.objects.filter( focus_id=focus_id ).exclude( id=cleaned_data['forening'].id ) if others.count(): other = others.all()[0] self.add_error( 'focus_id', ( f"Focus ID «{focus_id}» er allerede registrert på " f"foreningen {other.name}." ) ) # Validate the new forening type and parents relationship try: forening = Forening() forening.validate_relationships( simulate_type=type_, simulate_parents=parents, ) except ForeningWithItselfAsParent: self.add_error( 'parents', "%s kan ikke være underlagt seg selv." % forening.name ) except SentralForeningWithRelation: self.add_error( 'parents', "En sentral forening kan ikke ha noen koblinger til andre foreningstyper." ) except ForeningWithForeningParent: self.add_error( 'parents', "En forening kan ikke være underlagt en annen forening." ) except TurlagWithTurlagParent: self.add_error( 'parents', "Et turlag kan ikke være underlagt et annet turlag." ) except TurgruppeWithTurgruppeParent: self.add_error( 'parents', "En turgruppe kan ikke være underlagt en annen turgruppe." ) except ForeningWithTurlagParent: self.add_error( 'parents', "Foreninger kan ikke være underlagt turlag/turgrupper." ) except TurlagWithTurgruppeParent: self.add_error( 'parents', "Et turlag kan ikke være underlagt en turgruppe." ) return cleaned_data
def index(request, forening_id): current_forening = Forening.objects.get(id=forening_id) if current_forening not in request.user.all_foreninger(): raise PermissionDenied forening_users = list(User.objects.filter(foreninger=current_forening)) forening_users_by_parent = [] parent_ids = [p.id for p in current_forening.get_parents_deep()] forening_users_by_parent_all = list(User.objects.filter(foreninger__in=parent_ids)) # Prefetch and cache the actors memberids = [u.memberid for u in (forening_users + forening_users_by_parent)] for actor in Actor.get_personal_members().filter(memberid__in=memberids): cache.set('actor.%s' % actor.memberid, actor, settings.FOCUS_MEMBER_CACHE_PERIOD) # Safe to iterate without having n+1 issues # Filter on admins forening_users_by_parent = [] for user in forening_users_by_parent_all: for forening in user.all_foreninger(): if forening == current_forening and forening.role == 'admin': forening_users_by_parent.append(user) forening_users = sorted(forening_users, key=lambda u: u.get_full_name()) forening_users_by_parent = sorted(forening_users_by_parent, key=lambda u: u.get_full_name()) sherpa_admins = sorted(User.objects.filter(permissions__name='sherpa_admin'), key=lambda u: u.get_full_name()) # The parent choices are tricky to define in the forms API, so do it here. # Note that we're intentionally letting users choose parents among only those they have permission to. all_sorted = request.user.all_foreninger_sorted() parents_choices = { 'forening': all_sorted['forening'], 'turlag': all_sorted['turlag'], } # If the parent of the current forening isn't in the user's permissions, we still need to include that one as an # available parent so that they're able to make changes. if current_forening.type != 'sentral': for current_parent in current_forening.get_main_foreninger(): if current_parent not in parents_choices['forening'] and current_parent not in parents_choices['turlag']: parents_choices[current_parent.type].append(current_parent) context = { 'current_forening': current_forening, 'forening_users': forening_users, 'forening_users_by_parent': forening_users_by_parent, 'sherpa_admins': sherpa_admins, 'parents_choices': parents_choices, 'admin_user_search_char_length': settings.ADMIN_USER_SEARCH_CHAR_LENGTH } zipcode = current_forening.zipcode edit_form_zipcode_area = zipcode.area if zipcode is not None else '' if current_forening.contact_person is not None: choose_contact = 'person' contact_person = current_forening.contact_person.id contact_person_name = current_forening.contact_person.get_full_name() phone = current_forening.contact_person.get_phone_mobile() email = current_forening.contact_person.get_sherpa_email() elif current_forening.contact_person_name != '': choose_contact = 'person' contact_person = None contact_person_name = current_forening.contact_person_name phone = current_forening.phone email = current_forening.email else: choose_contact = 'forening' contact_person = None contact_person_name = '' phone = current_forening.phone email = current_forening.email edit_form = ExistingForeningDataForm(request.user, prefix='edit', initial={ 'forening': current_forening.id, 'parents': current_forening.parents.all(), 'name': current_forening.name, 'type': current_forening.type, 'group_type': current_forening.group_type, 'post_address': current_forening.post_address, 'visit_address': current_forening.visit_address, 'zipcode': zipcode.zipcode if zipcode is not None else '', 'counties': current_forening.counties.all(), 'choose_contact': choose_contact, 'contact_person': contact_person, 'contact_person_name': contact_person_name, 'phone': phone, 'email': email, 'organization_no': current_forening.organization_no, 'gmap_url': current_forening.gmap_url, 'facebook_url': current_forening.facebook_url, }) create_form = ForeningDataForm(request.user, prefix='create', initial={ 'zipcode': '', }) context.update({ 'edit_form': edit_form, 'create_form': create_form, 'edit_form_zipcode_area': edit_form_zipcode_area, }) if request.method == 'GET': return render(request, 'common/admin/forening/index.html', context) elif request.method == 'POST': if request.POST.get('form') == 'edit': edit_form = ExistingForeningDataForm(request.user, request.POST, prefix='edit') if edit_form.is_valid(): forening = edit_form.cleaned_data['forening'] forening.parents = edit_form.cleaned_data['parents'] forening.name = edit_form.cleaned_data['name'] forening.type = edit_form.cleaned_data['type'] if forening.type == 'turgruppe': forening.group_type = edit_form.cleaned_data['group_type'] else: forening.group_type = '' forening.post_address = edit_form.cleaned_data['post_address'] forening.visit_address = edit_form.cleaned_data['visit_address'] forening.zipcode = edit_form.cleaned_data['zipcode'] forening.counties = edit_form.cleaned_data['counties'] if edit_form.cleaned_data['choose_contact'] == 'person': if edit_form.cleaned_data['contact_person'] is not None: forening.contact_person = edit_form.cleaned_data['contact_person'] forening.contact_person_name = '' else: forening.contact_person = None forening.contact_person_name = edit_form.cleaned_data['contact_person_name'] else: forening.contact_person = None forening.contact_person_name = '' forening.phone = edit_form.cleaned_data['phone'] forening.email = edit_form.cleaned_data['email'] forening.organization_no = edit_form.cleaned_data['organization_no'] forening.gmap_url = edit_form.cleaned_data['gmap_url'] forening.facebook_url = edit_form.cleaned_data['facebook_url'] forening.save() messages.info(request, 'forening_save_success') cache.delete('foreninger.all.sorted_by_name') cache.delete('foreninger.all.sorted_by_name.with_active_url') cache.delete('foreninger.all.sorted_by_type') cache.delete('forening.%s' % forening.id) cache.delete('forening.main_foreninger.%s' % forening.id) return redirect('admin.forening.views.index', current_forening.id) else: context.update({'edit_form': edit_form}) return render(request, 'common/admin/forening/index.html', context) elif request.POST.get('form') == 'create': create_form = ForeningDataForm(request.user, request.POST, prefix='create') if create_form.is_valid(): forening = Forening() forening.name = create_form.cleaned_data['name'] forening.type = create_form.cleaned_data['type'] if forening.type == 'turgruppe': forening.group_type = create_form.cleaned_data['group_type'] else: forening.group_type = '' forening.post_address = create_form.cleaned_data['post_address'] forening.visit_address = create_form.cleaned_data['visit_address'] forening.zipcode = create_form.cleaned_data['zipcode'] if create_form.cleaned_data['choose_contact'] == 'person': if create_form.cleaned_data['contact_person'] is not None: forening.contact_person = create_form.cleaned_data['contact_person'] forening.contact_person_name = '' else: forening.contact_person = None forening.contact_person_name = create_form.cleaned_data['contact_person_name'] else: forening.contact_person = None forening.contact_person_name = '' forening.phone = create_form.cleaned_data['phone'] forening.email = create_form.cleaned_data['email'] forening.organization_no = create_form.cleaned_data['organization_no'] forening.gmap_url = create_form.cleaned_data['gmap_url'] forening.facebook_url = create_form.cleaned_data['facebook_url'] forening.save() # Set M2M-fields after the initial db-save forening.parents = create_form.cleaned_data['parents'] forening.counties = create_form.cleaned_data['counties'] # Add the current user as admin on the new forening role = ForeningRole( user=request.user, forening=forening, role='admin', ) role.save() # FIXME: We can't delete the permission cache for all users, so some may find that they can't edit # the new forening even though they should be able, until the cache (which is currently 24h) expires. cache.delete('user.%s.all_foreninger' % request.user.id) messages.info(request, 'forening_create_success') request.session['active_forening'] = forening.id cache.delete('foreninger.all.sorted_by_name') cache.delete('foreninger.all.sorted_by_name.with_active_url') cache.delete('foreninger.all.sorted_by_type') cache.delete('forening.%s' % forening.id) cache.delete('forening.main_foreninger.%s' % forening.id) # Since GET url == POST url, we need to specifically set the tab hashtag we want, or the existing # one (create) will be kept return redirect('%s#metadata' % reverse('admin.forening.views.index', args=[current_forening.id])) else: context.update({'create_form': create_form}) return render(request, 'common/admin/forening/index.html', context) else: return redirect('admin.forening.views.index', current_forening.id)
def forening(self): """Return the forening owning the account for this charge""" return Forening.get_by_stripe_id(self.account_id)
def clean(self): cleaned_data = super(ForeningDataForm, self).clean() if cleaned_data.get('choose_contact') == 'person': if cleaned_data.get('contact_person') is None and \ (cleaned_data.get('contact_person_name') is None or cleaned_data.get('contact_person_name') == ''): self.add_error( 'contact_person_name', u"Hvis det er en kontaktperson som kan kontaktes, må du oppgi et navn eller velge en person " \ u"fra medlemsregisteret.", ) type_ = cleaned_data.get('type') parents = cleaned_data.get('parents') if type_ in ['sentral', 'forening']: # In this case, the UI will have hidden the parents input, but it might still have a value, so # force it to empty. The hiding of the field should make this behavior intuitive. cleaned_data['parent'] = [] parents = [] # These types must have a parent, but that can't be enforced on the DB-level for *new* foreninger since parents # are a M2M-relationship (so the child needs to be saved before the parent can be related), so check it here. elif type_ in ['turlag', 'turgruppe'] and len(parents) == 0: self.add_error( 'parents', u"%s må ha en moderforening!" % ( 'Et turlag' if type_ == 'turlag' else 'En turgruppe', ) ) parents = None # Non DNT admins cannot *create* forening with type forening/sentral # Note that this might be legal in derived classes, so check this only for the base class # Shouldn't be possible without a manual POST if type(self) == ForeningDataForm and not self._user.is_admin_in_dnt_central() and type_ in ['sentral', 'forening']: self.add_error( 'type', u"Du har ikke tillatelse til å opprette sentrale grupper eller medlemsforeninger. Vennligst ta " \ u"kontakt med DNT sentralt.", ) # Validate the new forening type and parents relationship try: forening = Forening() forening.validate_relationships( simulate_type=type_, simulate_parents=parents, ) except ForeningWithItselfAsParent: # Shouldn't be possible without a manual POST self.add_error( 'parents', u"%s kan ikke være underlagt seg selv." % forening.name ) except SentralForeningWithRelation: # Shouldn't be possible without a manual POST self.add_error( 'parents', u"En sentral forening kan ikke ha noen koblinger til andre foreningstyper." ) except ForeningWithForeningParent: self.add_error( 'parents', u"En forening kan ikke være underlagt en annen forening." ) except TurlagWithTurlagParent: self.add_error( 'parents', u"Et turlag kan ikke være underlagt et annet turlag." ) except TurgruppeWithTurgruppeParent: self.add_error( 'parents', u"En turgruppe kan ikke være underlagt en annen turgruppe." ) except ForeningWithTurlagParent: self.add_error( 'parents', u"Foreninger kan ikke være underlagt turlag/turgrupper." ) except TurlagWithTurgruppeParent: self.add_error( 'parents', u"Et turlag kan ikke være underlagt en turgruppe." )
def admin_context(self, site): return { 'all_foreninger_sorted': Forening.get_all_sorted_with_type_data(), 'audiences': AktivitetAudience.AUDIENCE_CHOICES, 'categories': Aktivitet.CATEGORY_CHOICES, }
def all_foreninger_sorted(self): return Forening.sort(self.all_foreninger())