diff --git a/SciPost_v1/urls.py b/SciPost_v1/urls.py index ac8d32e7f95513d6aae3a5d11b8a4568408aee7d..f77a4e7437771b6ed4477f64b44322eae1c1ffc1 100644 --- a/SciPost_v1/urls.py +++ b/SciPost_v1/urls.py @@ -15,6 +15,8 @@ from journals.viewsets import PublicationViewSetForGoogleScholar from news.viewsets import NewsItemViewSet from journals.constants import REGEX_CHOICES from scipost import views as scipost_views +from organizations.views import OrganizationListView + # Journal URL Regex JOURNAL_REGEX = '(?P<doi_label>%s)' % REGEX_CHOICES @@ -64,12 +66,11 @@ urlpatterns = [ url(r'^proceedings/', include('proceedings.urls', namespace="proceedings")), url(r'^production/', include('production.urls', namespace="production")), url(r'^profiles/', include('profiles.urls', namespace="profiles")), - # TODO: partners to be deprecated in favour of sponsors - url(r'^partners/', include('partners.urls', namespace="partners")), url(r'^sponsors/', include('sponsors.urls', namespace="sponsors")), url(r'^stats/', include('stats.urls', namespace="stats")), - # Keep temporarily for historical reasons - url(r'^supporting_partners/', include('partners.urls', namespace="_partners")), + # Deprecated, keep temporarily for historical reasons + url(r'^partners/', OrganizationListView.as_view(), name='partners'), + url(r'^supporting_partners/', OrganizationListView.as_view(), name='partners'), ] if settings.DEBUG: diff --git a/organizations/views.py b/organizations/views.py index e1c2daed9cf664396a98b5bae469c01e9a40e2d9..fc70b5f9a8b8a8dc370c0ab0a736d38e2746ff8a 100644 --- a/organizations/views.py +++ b/organizations/views.py @@ -26,7 +26,6 @@ from funders.models import Funder from mails.utils import DirectMailUtil from mails.views import MailEditingSubView from organizations.decorators import has_contact -# from partners.models import ProspectivePartner, Partner DELPARTNERS from scipost.mixins import PermissionsMixin, PaginationMixin @@ -70,10 +69,6 @@ class OrganizationListView(PaginationMixin, ListView): context = super().get_context_data(*args, **kwargs) if self.request.user.has_perm('scipost.can_manage_organizations'): context['nr_funders_wo_organization'] = Funder.objects.filter(organization=None).count() - # context['nr_prospartners_wo_organization'] = ProspectivePartner.objects.filter( - # organization=None).count() DELPARTNERS - # context['nr_partners_wo_organization'] = Partner.objects.filter( - # organization=None).count() DELPARTNERS context['pubyears'] = range(int(timezone.now().strftime('%Y')), 2015, -1) context['countrycodes'] = [code['country'] for code in list( Organization.objects.all().distinct('country').values('country'))] diff --git a/partners/admin.py b/partners/admin.py deleted file mode 100644 index 2cdab75497a557ce16e0b43e3658a84036cf9b5b..0000000000000000000000000000000000000000 --- a/partners/admin.py +++ /dev/null @@ -1,65 +0,0 @@ -__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" -__license__ = "AGPL v3" - - -from django.contrib import admin - -# from .models import Contact, Partner, PartnerEvent, \ -# ProspectivePartner, ProspectiveContact, ProspectivePartnerEvent,\ -# MembershipAgreement, ContactRequest - - - -# class ContactToPartnerInline(admin.TabularInline): -# model = Contact.partners.through -# extra = 0 -# verbose_name = 'Contact' -# verbose_name_plural = 'Contacts' - - -# class ContactToUserInline(admin.StackedInline): -# model = Contact -# extra = 0 -# min_num = 0 -# verbose_name = 'Contact (Partners)' - - -# class ProspectiveContactInline(admin.TabularInline): -# model = ProspectiveContact -# extra = 0 - - -# class ProspectivePartnerEventInline(admin.TabularInline): -# model = ProspectivePartnerEvent -# extra = 0 - - -# class ProspectivePartnerAdmin(admin.ModelAdmin): -# inlines = (ProspectiveContactInline, ProspectivePartnerEventInline,) -# list_display = ('institution_name', 'date_received', 'date_processed', 'status') -# list_filter = ('kind', 'status') - - -# class PartnerEventInline(admin.TabularInline): -# model = PartnerEvent -# extra = 0 - - -# class PartnerAdmin(admin.ModelAdmin): -# search_fields = ('institution', ) -# inlines = ( -# ContactToPartnerInline, -# PartnerEventInline, -# ) - - -# class MembershipAgreementAdmin(admin.ModelAdmin): -# inlines = ( -# ) - - -# admin.site.register(Partner, PartnerAdmin) -# admin.site.register(Contact) -# admin.site.register(ContactRequest) -# admin.site.register(ProspectivePartner, ProspectivePartnerAdmin) -# admin.site.register(MembershipAgreement, MembershipAgreementAdmin) diff --git a/partners/decorators.py b/partners/decorators.py deleted file mode 100644 index d446b1b7dd029c398db4bfbee476de702c148014..0000000000000000000000000000000000000000 --- a/partners/decorators.py +++ /dev/null @@ -1,14 +0,0 @@ -__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" -__license__ = "AGPL v3" - - -from .models import Contact - - -def has_contact(user): - """Requires user to be related to any Contact.""" - try: - user.partner_contact - return True - except Contact.DoesNotExist: - return False diff --git a/partners/forms.py b/partners/forms.py deleted file mode 100644 index e5ea298704efea584bd7568bee769ce73110f152..0000000000000000000000000000000000000000 --- a/partners/forms.py +++ /dev/null @@ -1,479 +0,0 @@ -__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" -__license__ = "AGPL v3" - - -from django import forms -from django.contrib.auth.models import User, Group -from django.contrib.auth.password_validation import validate_password -from django.core.exceptions import ValidationError -from django.db import transaction -from django.db.models import Q - -from ajax_select.fields import AutoCompleteSelectField - -from captcha.fields import ReCaptchaField -from django_countries import countries -from django_countries.widgets import CountrySelectWidget -from django_countries.fields import LazyTypedChoiceField - -from .constants import PARTNER_KINDS, PROSPECTIVE_PARTNER_PROCESSED, CONTACT_TYPES,\ - PARTNER_STATUS_UPDATE, REQUEST_PROCESSED, REQUEST_DECLINED, CONTACT_GENERAL -from .models import Partner, ProspectivePartner, ProspectiveContact, ProspectivePartnerEvent,\ - Contact, PartnerEvent, MembershipAgreement, ContactRequest -from .utils import PartnerUtils - -from scipost.models import TITLE_CHOICES - - -class MembershipAgreementForm(forms.ModelForm): - class Meta: - model = MembershipAgreement - fields = ( - 'partner', - 'status', - 'date_requested', - 'start_date', - 'end_date', - 'duration', - 'offered_yearly_contribution' - ) - widgets = { - 'start_date': forms.TextInput(attrs={'placeholder': 'YYYY-MM-DD'}), - 'end_date': forms.TextInput(attrs={'placeholder': 'YYYY-MM-DD'}), - 'date_requested': forms.TextInput(attrs={'placeholder': 'YYYY-MM-DD'}), - } - - def save(self, current_user, commit=True): - agreement = super().save(commit=False) - if commit: - if agreement.partner and not self.instance.id: - # Create PartnerEvent if Agreement is new - event = PartnerEvent( - partner=agreement.partner, - event=PARTNER_STATUS_UPDATE, - comments='Membership Agreement added with start date %s' % agreement.start_date, - noted_by=current_user - ) - event.save() - # Save agreement afterwards to be able to detect edit/add difference - agreement.save() - return agreement - - -class ActivationForm(forms.ModelForm): - class Meta: - model = User - fields = [] - - description = forms.CharField(max_length=256, label="Title", required=False, - widget=forms.TextInput(attrs={ - 'placeholder': 'E.g.: Legal Agent at Stanford University'})) - kind = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, label="Contact type", - choices=CONTACT_TYPES) - password_new = forms.CharField(label='* Password', widget=forms.PasswordInput()) - password_verif = forms.CharField(label='* Verify password', widget=forms.PasswordInput(), - help_text='Your password must contain at least 8 characters') - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - try: - self.fields['kind'].initial = self.instance.partner_contact.kind - except Contact.DoesNotExist: - pass - - def clean(self, *args, **kwargs): - try: - self.instance.partner_contact - except Contact.DoesNotExist: - self.add_error(None, 'Your account is invalid, please contact the administrator.') - return super().clean(*args, **kwargs) - - def clean_password(self): - password = self.cleaned_data.get('password_new', '') - try: - validate_password(password, self.instance) - except ValidationError as error_message: - self.add_error('password_new', error_message) - return password - - def clean_password_verif(self): - if self.cleaned_data.get('password_new', '') != self.cleaned_data.get('password_verif', ''): - self.add_error('password_verif', 'Your password entries must match') - return self.cleaned_data.get('password_verif', '') - - @transaction.atomic - def activate_user(self): - if self.errors: - return forms.ValidationError - - # Activate account - self.instance.is_active = True - self.instance.set_password(self.cleaned_data['password_new']) - self.instance.save() - - # Set fields for Contact - self.instance.partner_contact.description = self.cleaned_data['description'] - self.instance.partner_contact.kind = self.cleaned_data['kind'] - self.instance.partner_contact.save() - - # Add permission groups to user - group = Group.objects.get(name='Partners Accounts') - self.instance.groups.add(group) - return self.instance - - -class PartnerEventForm(forms.ModelForm): - class Meta: - model = PartnerEvent - fields = ( - 'event', - 'comments', - ) - - -class PartnerForm(forms.ModelForm): - organization = AutoCompleteSelectField('organization_lookup') - - class Meta: - model = Partner - fields = ( - 'organization', - 'status', - 'main_contact' - ) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.fields['main_contact'].queryset = self.instance.contact_set.all() - - -class RequestContactForm(forms.ModelForm): - class Meta: - model = ContactRequest - fields = ( - 'email', - 'title', - 'first_name', - 'last_name', - 'kind', - ) - - -class ProcessRequestContactForm(RequestContactForm): - decision = forms.ChoiceField(choices=((None, 'No decision'), ('accept', 'Accept'), ('decline', 'Decline')), - widget=forms.RadioSelect, label='Accept or Decline') - - class Meta: - model = ContactRequest - fields = RequestContactForm.Meta.fields + ('partner',) - - def process_request(self, current_user): - if self.cleaned_data['decision'] == 'accept': - self.instance.status = REQUEST_PROCESSED - self.instance.save() - contactForm = NewContactForm({ - 'title': self.cleaned_data['title'], - 'email': self.cleaned_data['email'], - 'first_name': self.cleaned_data['first_name'], - 'last_name': self.cleaned_data['last_name'], - 'kind': self.cleaned_data['kind'], - }, partner=self.cleaned_data['partner']) - contactForm.is_valid() - contactForm.save(current_user=current_user) - elif self.cleaned_data['decision'] == 'decline': - self.instance.status = REQUEST_DECLINED - self.instance.save() - - -class RequestContactFormSet(forms.BaseModelFormSet): - def process_requests(self, current_user): - """ - Process all requests if status is eithter accept or decline. - """ - for form in self.forms: - form.process_request(current_user=current_user) - - -class ContactForm(forms.ModelForm): - """ - This Contact form is mainly used for editing Contact instances. - """ - class Meta: - model = Contact - fields = ( - 'kind', - ) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.fields['kind'].required = False - - -class NewContactForm(ContactForm): - """ - This Contact form is used to create new Contact instances, as it will also handle - possible sending and activation of User instances coming with the new Contact. - """ - title = forms.ChoiceField(choices=TITLE_CHOICES, label='Title') - first_name = forms.CharField() - last_name = forms.CharField() - email = forms.CharField() - existing_user = None - - def __init__(self, *args, **kwargs): - """ - Partner is a required argument to tell the formset which Partner the Contact - is being edited for in the current form. - """ - self.partner = kwargs.pop('partner') - super().__init__(*args, **kwargs) - - def clean_email(self): - """ - Check if User already is known in the system. - """ - email = self.cleaned_data['email'] - try: - self.existing_user = User.objects.get(email=email) - if not self.data.get('confirm_use_existing', '') == 'on': - # Do not give error if user wants to use existing User - self.add_error('email', 'This User is already registered.') - self.fields['confirm_use_existing'] = forms.BooleanField( - required=False, initial=False, label='Use the existing user instead: %s %s' - % (self.existing_user.first_name, - self.existing_user.last_name)) - except User.DoesNotExist: - pass - return email - - @transaction.atomic - def save(self, current_user, commit=True): - """ - If existing user is found, add it to the Partner. - """ - if self.existing_user and self.data.get('confirm_use_existing', '') == 'on': - # Do not create new Contact - try: - # Link Contact to new Partner - contact = self.existing_user.partner_contact - contact.partners.add(self.partner) - except Contact.DoesNotExist: - # Not yet a 'Contact-User' - contact = super().save(commit=False) - contact.title = self.existing_user.contributor.title - contact.user = self.existing_user - contact.save() - contact.partners.add(self.partner) - return contact - - # Create complete new Account (User + Contact) - user = User( - first_name=self.cleaned_data['first_name'], - last_name=self.cleaned_data['last_name'], - email=self.cleaned_data['email'], - username=self.cleaned_data['email'], - is_active=False, - ) - user.save() - contact = Contact( - user=user, - title=self.cleaned_data['title'], - kind=self.cleaned_data['kind'] - ) - contact.generate_key() - contact.save() - contact.partners.add(self.partner) - - # Send email for activation - PartnerUtils.load({'contact': contact}) - PartnerUtils.email_contact_new_for_activation(current_user=current_user) - return contact - - -class ContactFormset(forms.BaseModelFormSet): - """ - Use custom formset to make sure the delete action will not delete an entire Contact - if the Contact still has relations with other Partners. - """ - def __init__(self, *args, **kwargs): - """ - Partner is a required argument to tell the formset which Partner the Contact - is being edited for in the current form. - """ - self.partner = kwargs.pop('partner') - super().__init__(*args, **kwargs) - - def delete_existing(self, obj, commit=True): - '''Deletes an existing model instance.''' - if commit: - obj.delete_or_remove_partner(self.partner) - - -class PromoteToPartnerForm(forms.ModelForm): - organization = AutoCompleteSelectField('organization_lookup') - - class Meta: - model = ProspectivePartner - fields = ( - 'kind', - 'institution_name', - 'country', - ) - - def promote_to_partner(self, current_user): - partner = Partner( - organization=self.cleaned_data['organization'], - main_contact=None - ) - partner.save() - event = PartnerEvent( - partner=partner, - event=PARTNER_STATUS_UPDATE, - comments='ProspectivePartner has been upgraded to Partner by %s %s' - % (current_user.first_name, current_user.last_name), - noted_by=current_user - ) - event.save() - - # Close Prospect - self.instance.status = PROSPECTIVE_PARTNER_PROCESSED - self.instance.save() - return partner - - -class PromoteToContactForm(forms.ModelForm): - """ - This form is used to create a new `partners.Contact` - """ - promote = forms.BooleanField(label='Activate/Promote this contact', initial=True, - required=False) - kind = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, initial=[CONTACT_GENERAL], - label='Contact types', choices=CONTACT_TYPES, required=False) - - class Meta: - model = ProspectiveContact - fields = ( - 'title', - 'first_name', - 'last_name', - 'email', - ) - - def clean_email(self): - """ - Check if email address is already used. - """ - email = self.cleaned_data['email'] - if not self.cleaned_data.get('promote', False): - # Don't promote the Contact - return email - if User.objects.filter(Q(email=email) | Q(username=email)).exists(): - self.add_error('email', 'This emailadres has already been used.') - return email - - @transaction.atomic - def promote_contact(self, partner, current_user): - """ - Promote ProspectiveContact's to Contact's related to a certain Partner. - The status update after promotion is handled outside this method, in the Partner model. - """ - if not self.cleaned_data.get('promote', False): - # Don't promote the Contact - return - - # How to handle empty instances? - if self.errors: - return forms.ValidationError # Is this a valid exception? - - # Create a new User and Contact linked to the partner given - contact_form = NewContactForm(self.cleaned_data, partner=partner) - if contact_form.is_valid(): - return contact_form.save(current_user=current_user) - raise forms.ValidationError('NewContactForm invalid. Please contact Admin.') - - -class PromoteToContactFormset(forms.BaseModelFormSet): - """ - This is a formset to process multiple `PromoteToContactForm`s at the same time - designed for the 'promote prospect to partner' action. - """ - def save(self, *args, **kwargs): - raise DeprecationWarning(("This formset is not meant to used with the default" - " `save` method. User the `promote_contacts` instead.")) - - @transaction.atomic - def promote_contacts(self, partner, current_user): - """ - Promote ProspectiveContact's to Contact's related to a certain Partner. - """ - contacts = [] - for form in self.forms: - new_contact = form.promote_contact(partner, current_user) - if new_contact: - contacts.append(new_contact) - try: - partner.main_contact = contacts[0] - except IndexError: - # No contacts at all means no main-contact as well... - pass - partner.save() - return contacts - - -ContactModelFormset = forms.modelformset_factory(ProspectiveContact, PromoteToContactForm, - formset=PromoteToContactFormset, extra=0) - - -class ProspectivePartnerForm(forms.ModelForm): - """ - This form is used to internally add a ProspectivePartner. - If an external agent requests membership of the SPB, - the MembershipQueryForm below is used instead. - """ - class Meta: - model = ProspectivePartner - fields = ('kind', 'institution_name', 'country') - - -class ProspectiveContactForm(forms.ModelForm): - class Meta: - model = ProspectiveContact - fields = '__all__' - widgets = {'prospartner': forms.HiddenInput()} - - -class ProspectivePartnerEventForm(forms.ModelForm): - class Meta: - model = ProspectivePartnerEvent - fields = ('event', 'comments') - widgets = { - 'comments': forms.Textarea(attrs={'cols': 16, 'rows': 3}), - } - - -class ProspectivePartnerOrganizationSelectForm(forms.ModelForm): - organization = AutoCompleteSelectField('organization_lookup') - - class Meta: - model = ProspectivePartner - fields = [] - - -class MembershipQueryForm(forms.Form): - """ - This form is to be used by an agent of the prospective Partner, - in order to request more information about potentially joining the SPB. - """ - title = forms.ChoiceField(choices=TITLE_CHOICES, label='* Your title') - first_name = forms.CharField(label='* Your first name', max_length=100) - last_name = forms.CharField(label='* Your last name', max_length=100) - email = forms.EmailField(label='* Your email address') - role = forms.CharField(label='* Your role in your organization') - partner_kind = forms.ChoiceField(choices=PARTNER_KINDS, label='* Partner kind') - institution_name = forms.CharField(label='* Name of your institution') - country = LazyTypedChoiceField( - choices=countries, label='* Country', initial='NL', - widget=CountrySelectWidget(layout=( - '{widget}<img class="country-select-flag" id="{flag_id}"' - ' style="margin: 6px 4px 0" src="{country.flag}">'))) - captcha = ReCaptchaField(attrs={'theme': 'clean'}, label='*Please verify to continue:') diff --git a/partners/managers.py b/partners/managers.py deleted file mode 100644 index 27b99afbcd155cc998a5e4c211d9c2fb7be55cd9..0000000000000000000000000000000000000000 --- a/partners/managers.py +++ /dev/null @@ -1,40 +0,0 @@ -__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" -__license__ = "AGPL v3" - - -from django.db import models -from django.utils import timezone - -from .constants import MEMBERSHIP_SUBMITTED, PROSPECTIVE_PARTNER_PROCESSED, REQUEST_INITIATED - - -class ContactRequestManager(models.Manager): - def awaiting_processing(self): - return self.filter(status=REQUEST_INITIATED) - - -class ProspectivePartnerManager(models.Manager): - def not_yet_partner(self): - return self.exclude(status=PROSPECTIVE_PARTNER_PROCESSED) - - -class PartnerManager(models.Manager): - def my_partners(self, current_user): - """ - Filter out my Partners if user is not a PartnerAdmin. - """ - if current_user.has_perm('scipost.can_view_partners'): - return self.all() - return self.filter(contact=current_user.partner_contact) - - -class MembershipAgreementManager(models.Manager): - def submitted(self): - return self.filter(status=MEMBERSHIP_SUBMITTED) - - def open_to_partner(self): - return self.exclude(status=MEMBERSHIP_SUBMITTED) - - def now_active(self): - return self.filter(start_date__lte=timezone.now().date(), - end_date__gte=timezone.now().date()) diff --git a/partners/models.py b/partners/models.py deleted file mode 100644 index ff3f57f3d0af53a45a446e0f5bd76af84d21c416..0000000000000000000000000000000000000000 --- a/partners/models.py +++ /dev/null @@ -1,296 +0,0 @@ -__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" -__license__ = "AGPL v3" - - -import datetime -import hashlib -import random -import string - -from django.contrib.auth.models import User -from django.contrib.postgres.fields import JSONField -from django.db import models -from django.db.models import Sum -from django.utils import timezone -from django.urls import reverse - -from django_countries.fields import CountryField - -from .constants import ( - PARTNER_KINDS, PARTNER_STATUS, MEMBERSHIP_DURATION, PARTNER_EVENTS, - PROSPECTIVE_PARTNER_STATUS, PROSPECTIVE_PARTNER_EVENTS, MEMBERSHIP_AGREEMENT_STATUS, - PROSPECTIVE_PARTNER_ADDED, PARTNER_KIND_UNI_LIBRARY) -from .constants import ( - PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT, PROSPECTIVE_PARTNER_APPROACHED, PARTNER_INITIATED, - PROSPECTIVE_PARTNER_EVENT_INITIATE_NEGOTIATION, PROSPECTIVE_PARTNER_PROCESSED, CONTACT_TYPES, - PROSPECTIVE_PARTNER_NEGOTIATING, PROSPECTIVE_PARTNER_EVENT_MARKED_AS_UNINTERESTED, - REQUEST_STATUSES, PROSPECTIVE_PARTNER_UNINTERESTED, PROSPECTIVE_PARTNER_EVENT_PROMOTED, - REQUEST_INITIATED) - -# from .managers import ( -# MembershipAgreementManager, ProspectivePartnerManager, PartnerManager, ContactRequestManager) - -from journals.models import Publication, PublicationAuthorsTable, OrgPubFraction - -from scipost.constants import TITLE_CHOICES -from scipost.fields import ChoiceArrayField -from scipost.models import get_sentinel_user, Contributor -from scipost.storage import SecureFileStorage - -now = timezone.now() - - - - -######################## -# Prospective Partners # -######################## - -# # TODO: to be deleted, use Organization instead -# class ProspectivePartner(models.Model): -# """A prospect Partner is a Partner without explicit contract with SciPost yet.""" - -# organization = models.OneToOneField('organizations.Organization', on_delete=models.CASCADE, -# blank=True, null=True) -# kind = models.CharField(max_length=32, choices=PARTNER_KINDS, default=PARTNER_KIND_UNI_LIBRARY) -# institution_name = models.CharField(max_length=256) -# country = CountryField() -# date_received = models.DateTimeField(auto_now_add=True) -# date_processed = models.DateTimeField(blank=True, null=True) -# status = models.CharField(max_length=32, choices=PROSPECTIVE_PARTNER_STATUS, -# default=PROSPECTIVE_PARTNER_ADDED) - -# objects = ProspectivePartnerManager() - -# def __str__(self): -# return '%s (received %s), %s' % (self.institution_name, -# self.date_received.strftime("%Y-%m-%d"), -# self.get_status_display()) - -# @property -# def is_promoted_to_partner(self): -# """Check if Prospect is already known to be a Partner.""" -# return self.status == PROSPECTIVE_PARTNER_PROCESSED - -# def update_status_from_event(self, event): -# if event == PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT: -# self.status = PROSPECTIVE_PARTNER_APPROACHED -# elif event == PROSPECTIVE_PARTNER_EVENT_INITIATE_NEGOTIATION: -# self.status = PROSPECTIVE_PARTNER_NEGOTIATING -# elif event == PROSPECTIVE_PARTNER_EVENT_MARKED_AS_UNINTERESTED: -# self.status = PROSPECTIVE_PARTNER_UNINTERESTED -# elif event == PROSPECTIVE_PARTNER_EVENT_PROMOTED: -# self.status = PROSPECTIVE_PARTNER_PROCESSED -# self.save() - - -# # TODO: to be deleted, superseded by organizations.ContactPerson -# class ProspectiveContact(models.Model): -# """ -# A ProspectiveContact is a person's name and contact details, with a -# link to a Prospective Partner and a role within it. -# It does not have a corresponding User object. -# It is meant to be used internally at SciPost, during Partner mining. -# """ -# prospartner = models.ForeignKey('partners.ProspectivePartner', on_delete=models.CASCADE, -# related_name='prospective_contacts') -# title = models.CharField(max_length=4, choices=TITLE_CHOICES) -# first_name = models.CharField(max_length=64) -# last_name = models.CharField(max_length=64) -# email = models.EmailField() -# role = models.CharField(max_length=128) - -# def __str__(self): -# return "%s %s %s" % (self.get_title_display(), self.first_name, self.last_name) - - -# # TODO: delete, superseded by OrganizationEvent -# class ProspectivePartnerEvent(models.Model): -# prospartner = models.ForeignKey('partners.ProspectivePartner', on_delete=models.CASCADE) -# event = models.CharField(max_length=64, choices=PROSPECTIVE_PARTNER_EVENTS) -# comments = models.TextField(blank=True) -# noted_on = models.DateTimeField(auto_now_add=True) -# noted_by = models.ForeignKey('scipost.Contributor', -# on_delete=models.SET(get_sentinel_user), -# blank=True, null=True) - -# def __str__(self): -# return '%s: %s' % (self.prospartner, self.get_event_display()) - - -########################### -# Partner-related objects # -########################### - -# class ContactRequest(models.Model): -# """ -# A ContactRequest request for a new Contact usually made by another Contact. -# The requests are saved to this separate model to also be able to request new -# Contact links if a Contact is already registered, but not linked to a specific Partner. -# """ -# email = models.EmailField() -# kind = ChoiceArrayField(models.CharField(max_length=4, choices=CONTACT_TYPES)) -# first_name = models.CharField(max_length=64) -# last_name = models.CharField(max_length=64) -# title = models.CharField(max_length=4, choices=TITLE_CHOICES) -# description = models.CharField(max_length=256, blank=True) -# partner = models.ForeignKey('partners.Partner', on_delete=models.CASCADE) -# status = models.CharField(max_length=4, choices=REQUEST_STATUSES, default=REQUEST_INITIATED) - -# objects = ContactRequestManager() - -# def __str__(self): -# return '%s %s %s' % (self.get_title_display(), self.first_name, self.last_name) - - -# class Contact(models.Model): -# """ -# A Contact is a simple form of User which is meant -# to be associated to Partner objects -# (main contact, financial/technical contact etc). -# Contacts and Contributors have different rights. -# """ -# user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True, -# related_name='partner_contact') -# kind = ChoiceArrayField(models.CharField(max_length=4, choices=CONTACT_TYPES)) -# title = models.CharField(max_length=4, choices=TITLE_CHOICES) -# description = models.CharField(max_length=256, blank=True) -# partners = models.ManyToManyField('partners.Partner', -# help_text=('All Partners (+related Organizations)' -# ' the Contact is related to.')) -# activation_key = models.CharField(max_length=40, blank=True) -# key_expires = models.DateTimeField(default=timezone.now) - -# def __str__(self): -# return '%s %s, %s' % (self.get_title_display(), self.user.last_name, self.user.first_name) - -# def generate_key(self, feed=''): -# """ -# Generate and save a new activation_key for the Contact, given a certain feed. -# """ -# for i in range(5): -# feed += random.choice(string.ascii_letters) -# feed = feed.encode('utf8') -# salt = self.user.username.encode('utf8') -# self.activation_key = hashlib.sha1(salt + feed).hexdigest() -# self.key_expires = now + datetime.timedelta(days=2) - -# def save(self, *args, **kwargs): -# if not self.activation_key: -# self.generate_key() -# super().save(*args, **kwargs) - -# def delete_or_remove_partner(self, partner, *args, **kwargs): -# """ -# Custom `delete` method as the contact does not always need to be deleted, -# but sometimes just the link with a specific partner needs to be removed. -# """ -# self.partners.remove(partner) -# if self.partners.exists(): -# return self -# try: -# # User also has a Contributor-side, do not remove complete User -# self.user.contributor -# return super().delete(*args, **kwargs) -# except Contributor.DoesNotExist: -# # Remove User; casade-remove this Contact -# self.user.delete() -# return self - -# @property -# def kind_display(self): -# """ -# Due to a lack of support to use get_FOO_display in a ArrayField, one has to create -# one 'manually'. -# """ -# choices = dict(CONTACT_TYPES) -# return ', '.join([choices[value] for index, value in enumerate(self.kind)]) - - -# # TODO: delete, use Organizations instead -# class Partner(models.Model): -# """ -# Supporting Partners. -# These are the official Partner objects created by SciPost Admin. -# """ -# organization = models.OneToOneField('organizations.Organization', on_delete=models.CASCADE, -# blank=True, null=True) -# status = models.CharField(max_length=16, choices=PARTNER_STATUS, default=PARTNER_INITIATED) -# main_contact = models.ForeignKey('partners.Contact', on_delete=models.SET_NULL, -# blank=True, null=True, related_name='partner_main_contact') - -# objects = PartnerManager() - -# def __str__(self): -# return self.organization.__str__() + ' (' + self.get_status_display() + ')' - -# def get_absolute_url(self): -# return reverse('partners:partner_view', args=(self.id,)) - -# def get_latest_active_agreement(self): -# return self.agreements.now_active().order_by('start_date').first() - -# @property -# def has_all_contacts(self): -# """ -# Determine if Partner has all available Contact Types available. -# """ -# raise NotImplemented - - -# # TODO: delete, superseded by OrganizationEvent -# class PartnerEvent(models.Model): -# partner = models.ForeignKey('partners.Partner', on_delete=models.CASCADE, -# related_name='events') -# event = models.CharField(max_length=64, choices=PARTNER_EVENTS) -# comments = models.TextField(blank=True) -# noted_on = models.DateTimeField(auto_now_add=True) -# noted_by = models.ForeignKey(User, on_delete=models.CASCADE) - -# def __str__(self): -# return '%s: %s' % (str(self.partner), self.get_event_display()) - - -# # TODO: delete, use finances.Subsidy instead -# class MembershipAgreement(models.Model): -# """ -# Agreement for membership of the Supporting Partners Board. -# A new instance is created each time an Agreement is made or renewed. -# """ -# partner = models.ForeignKey('partners.Partner', on_delete=models.CASCADE, -# blank=True, null=True, related_name='agreements') -# status = models.CharField(max_length=16, choices=MEMBERSHIP_AGREEMENT_STATUS) -# date_requested = models.DateField() -# start_date = models.DateField() -# end_date = models.DateField() -# duration = models.DurationField(choices=MEMBERSHIP_DURATION) -# offered_yearly_contribution = models.SmallIntegerField(default=0, help_text="Yearly contribution in euro's (€)") - -# objects = MembershipAgreementManager() - -# def __str__(self): -# return (str(self.partner) + -# ' [' + self.get_duration_display() + -# ' from ' + self.start_date.strftime('%Y-%m-%d') + ']') - -# def get_absolute_url(self): -# return reverse('partners:agreement_details', args=(self.id,)) - - -# TODO: delete, use finances.SubsidyAttachment instead -# class PartnersAttachment(models.Model): -# """ -# An Attachment which can (in the future) be related to a Partner, Contact, MembershipAgreement, -# etc. -# """ -# attachment = models.FileField(upload_to='UPLOADS/PARTNERS/ATTACHMENTS', -# storage=SecureFileStorage()) -# name = models.CharField(max_length=128) -# agreement = models.ForeignKey('partners.MembershipAgreement', related_name='attachments', -# blank=True) - -# objects = PartnersAttachmentManager() - -# def get_absolute_url(self): -# if self.agreement: -# return reverse('partners:agreement_attachments', args=(self.agreement.id, self.id)) diff --git a/partners/urls.py b/partners/urls.py deleted file mode 100644 index ee68e348b42bd85acb1d78a88804a31a3103e4ce..0000000000000000000000000000000000000000 --- a/partners/urls.py +++ /dev/null @@ -1,52 +0,0 @@ -__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" -__license__ = "AGPL v3" - - -from django.conf.urls import url - -from . import views - -urlpatterns = [ - # url(r'^$', views.supporting_partners, name='partners'), - # url(r'^dashboard$', views.dashboard, name='dashboard'), - # url(r'^membership_request$', views.membership_request, name='membership_request'), - # url(r'^process_contact_requests$', views.process_contact_requests, name='process_contact_requests'), - - # # Prospects - # url(r'^prospects/add$', views.add_prospective_partner, - # name='add_prospective_partner'), - # url(r'^prospects/prospartner_link_organization/$', - # views.LinkProspectivePartnerToOrganizationView.as_view(), - # name='prospartner_link_organization'), - # url(r'^prospects/contacts/(?P<contact_id>[0-9]+)/email$', - # views.email_prospartner_contact, name='email_prospartner_contact'), - # url(r'^prospects/contacts/(?P<contact_id>[0-9]+)/email/(?P<mail>followup)$', - # views.email_prospartner_contact, name='email_prospartner_contact'), - - # url(r'^prospects/(?P<prospartner_id>[0-9]+)/contacts/add$', - # views.add_prospartner_contact, name='add_prospartner_contact'), - # url(r'^prospects/(?P<prospartner_id>[0-9]+)/promote$', - # views.promote_prospartner, name='promote_prospartner'), - # url(r'^prospects/(?P<prospartner_id>[0-9]+)/email_generic$', - # views.email_prospartner_generic, name='email_prospartner_generic'), - # url(r'^prospects/(?P<prospartner_id>[0-9]+)/email_generic/(?P<mail>followup)$', - # views.email_prospartner_generic, name='email_prospartner_generic'), - # url(r'^prospects/(?P<prospartner_id>[0-9]+)/events/add$', - # views.add_prospartner_event, name='add_prospartner_event'), - - # # Agreements - # url(r'agreements/new$', views.add_agreement, name='add_agreement'), - # url(r'agreements/(?P<agreement_id>[0-9]+)$', views.agreement_details, - # name='agreement_details'), - - # # Users - # url(r'activate/(?P<activation_key>.+)$', views.activate_account, name='activate_account'), - - # # Partners - # url(r'(?P<partner_id>[0-9]+)$', views.partner_view, name='partner_view'), - # url(r'(?P<partner_id>[0-9]+)/edit$', views.partner_edit, name='partner_edit'), - # url(r'(?P<partner_id>[0-9]+)/contacts/add$', views.partner_add_contact, - # name='partner_add_contact'), - # url(r'(?P<partner_id>[0-9]+)/contacts/request$', views.partner_request_contact, - # name='partner_request_contact'), -] diff --git a/partners/views.py b/partners/views.py deleted file mode 100644 index d6ec017769d77187218f2c340f64099d01737510..0000000000000000000000000000000000000000 --- a/partners/views.py +++ /dev/null @@ -1,437 +0,0 @@ -__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" -__license__ = "AGPL v3" - - -import mimetypes - -from django.contrib import messages -from django.contrib.auth.decorators import login_required -from django.core.urlresolvers import reverse_lazy -from django.db import transaction -from django.db.models import F -from django.forms import modelformset_factory -from django.http import HttpResponse -from django.shortcuts import get_object_or_404, render, reverse, redirect -from django.utils import timezone -from django.views.generic.detail import DetailView -from django.views.generic.edit import CreateView, UpdateView, DeleteView -from django.views.generic.list import ListView - -from guardian.decorators import permission_required - -from mails.views import MailEditingSubView - -from .constants import PROSPECTIVE_PARTNER_REQUESTED,\ - PROSPECTIVE_PARTNER_APPROACHED, PROSPECTIVE_PARTNER_ADDED,\ - PROSPECTIVE_PARTNER_EVENT_REQUESTED, PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT,\ - PROSPECTIVE_PARTNER_FOLLOWED_UP -# from .models import Partner, ProspectivePartner, ProspectiveContact, ContactRequest,\ -# ProspectivePartnerEvent, MembershipAgreement, Contact -# from .forms import ProspectivePartnerForm, ProspectiveContactForm,\ -# PromoteToPartnerForm,\ -# ProspectivePartnerEventForm, ProspectivePartnerOrganizationSelectForm, MembershipQueryForm,\ -# PartnerForm, ContactForm, ContactFormset, ContactModelFormset,\ -# NewContactForm, ActivationForm, PartnerEventForm,\ -# MembershipAgreementForm, RequestContactForm, RequestContactFormSet,\ -# ProcessRequestContactForm - - -from funders.models import Funder - -from journals.models import Publication - -from scipost.mixins import PermissionsMixin - - - -# def supporting_partners(request): -# current_agreements = MembershipAgreement.objects.now_active() -# context = { -# 'current_agreements': current_agreements -# } -# if request.user.groups.filter(name='Editorial Administrators').exists(): -# # Show Agreements to Administrators only! -# prospective_agreements = MembershipAgreement.objects.submitted().order_by('date_requested') -# context['prospective_partners'] = prospective_agreements -# return render(request, 'partners/supporting_partners.html', context) - - -# @login_required -# @permission_required('scipost.can_read_partner_page', return_403=True) -# def dashboard(request): -# """Administration page for Partners and Prospective Partners. - -# This page is meant as a personal page for Partners, where they will for example be able -# to read their personal data and agreements. -# """ -# context = {} -# try: -# context['personal_agreements'] = (MembershipAgreement.objects.open_to_partner() -# .filter(partner__contact=request.user.partner_contact)) -# except Contact.DoesNotExist: -# pass - -# if request.user.has_perm('scipost.can_manage_SPB'): -# context['contact_requests_count'] = ContactRequest.objects.awaiting_processing().count() -# context['inactivate_contacts_count'] = Contact.objects.filter(user__is_active=False).count() -# context['partners'] = Partner.objects.all() -# context['prospective_partners'] = ProspectivePartner.objects.order_by( -# 'country', 'institution_name') -# context['nr_prospartners_wo_organization'] = ProspectivePartner.objects.filter( -# organization=None).count() -# context['ppevent_form'] = ProspectivePartnerEventForm() -# context['agreements'] = MembershipAgreement.objects.order_by('date_requested') -# return render(request, 'partners/dashboard.html', context) - - -# @transaction.atomic -# def membership_request(request): -# query_form = MembershipQueryForm(request.POST or None) -# if query_form.is_valid(): -# prospartner = ProspectivePartner( -# kind=query_form.cleaned_data['partner_kind'], -# institution_name=query_form.cleaned_data['institution_name'], -# country=query_form.cleaned_data['country'], -# date_received=timezone.now(), -# status=PROSPECTIVE_PARTNER_REQUESTED, -# ) -# prospartner.save() -# contact = ProspectiveContact( -# prospartner=prospartner, -# title=query_form.cleaned_data['title'], -# first_name=query_form.cleaned_data['first_name'], -# last_name=query_form.cleaned_data['last_name'], -# email=query_form.cleaned_data['email'], -# ) -# contact.save() -# prospartnerevent = ProspectivePartnerEvent( -# prospartner=prospartner, -# event=PROSPECTIVE_PARTNER_EVENT_REQUESTED) -# prospartnerevent.save() -# ack_message = ('Thank you for your SPB Membership query. ' -# 'We will get back to you in the very near future ' -# 'with further details.') -# context = {'ack_message': ack_message} -# return render(request, 'scipost/acknowledgement.html', context) -# context = {'query_form': query_form} -# return render(request, 'partners/membership_request.html', context) - - -# @permission_required('scipost.can_manage_organizations', return_403=True) -# @transaction.atomic -# def promote_prospartner(request, prospartner_id): -# prospartner = get_object_or_404(ProspectivePartner.objects.not_yet_partner(), -# pk=prospartner_id) -# form = PromoteToPartnerForm(request.POST or None, instance=prospartner) -# contact_formset = ContactModelFormset(request.POST or None, -# queryset=prospartner.prospective_contacts.all()) -# if form.is_valid() and contact_formset.is_valid(): -# partner = form.promote_to_partner(request.user) -# contacts = contact_formset.promote_contacts(partner, request.user) -# messages.success(request, ('<h3>Upgraded Partner %s</h3>' -# '%i contacts have received a validation mail.') % -# (str(partner), len(contacts))) -# return redirect(reverse('partners:dashboard')) -# context = {'form': form, 'contact_formset': contact_formset} -# return render(request, 'partners/promote_prospartner.html', context) - - -# class LinkProspectivePartnerToOrganizationView(PermissionsMixin, UpdateView): -# """ -# For an existing ProspectivePartner instance, specify the link to an Organization. -# """ -# permission_required = 'scipost.can_manage_organizations' -# model = ProspectivePartner -# form_class = ProspectivePartnerOrganizationSelectForm -# template_name = 'partners/prospartner_link_organization.html' -# success_url = reverse_lazy('partners:prospartner_link_organization') - -# def get_object(self): -# prospectivepartner = ProspectivePartner.objects.filter( -# organization=None).first() -# return prospectivepartner - -# def form_valid(self, form): -# form.instance.organization = form.cleaned_data['organization'] -# return super().form_valid(form) - - - - -############### -# Partner views -############### -# @permission_required('scipost.can_view_own_partner_details', return_403=True) -# def partner_view(request, partner_id): -# partner = get_object_or_404(Partner.objects.my_partners(request.user), id=partner_id) -# form = PartnerEventForm(request.POST or None) -# if form.is_valid(): -# event = form.save(commit=False) -# event.partner = partner -# event.noted_by = request.user -# event.save() -# messages.success(request, 'Added a new event to Partner.') -# return redirect(partner.get_absolute_url()) -# context = { -# 'partner': partner, -# 'form': form -# } -# return render(request, 'partners/partners_detail.html', context) - - -# @permission_required('scipost.can_manage_SPB', return_403=True) -# @transaction.atomic -# def partner_edit(request, partner_id): -# partner = get_object_or_404(Partner, id=partner_id) - -# # Start/fill forms -# form = PartnerForm(request.POST or None, instance=partner) -# ContactModelFormset = modelformset_factory(Contact, ContactForm, can_delete=True, extra=0, -# formset=ContactFormset) -# contact_formset = ContactModelFormset(request.POST or None, partner=partner, -# queryset=partner.contact_set.all()) - -# # Validate forms for POST request -# if form.is_valid() and contact_formset.is_valid(): -# form.save() -# contact_formset.save() -# messages.success(request, 'Partner saved') -# return redirect(reverse('partners:partner_view', args=(partner.id,))) -# context = { -# 'form': form, -# 'contact_formset': contact_formset -# } -# return render(request, 'partners/partner_edit.html', context) - - -# @permission_required('scipost.can_manage_SPB', return_403=True) -# def partner_add_contact(request, partner_id): -# partner = get_object_or_404(Partner, id=partner_id) -# form = NewContactForm(request.POST or None, partner=partner) -# if form.is_valid(): -# contact = form.save(current_user=request.user) -# messages.success(request, '<h3>Created contact: %s</h3>Email has been sent.' -# % str(contact)) -# return redirect(reverse('partners:dashboard')) -# context = { -# 'partner': partner, -# 'form': form -# } -# return render(request, 'partners/partner_add_contact.html', context) - - -# @permission_required('scipost.can_view_own_partner_details', return_403=True) -# def partner_request_contact(request, partner_id): -# partner = get_object_or_404(Partner.objects.my_partners(request.user), id=partner_id) -# form = RequestContactForm(request.POST or None) -# if form.is_valid(): -# contact_request = form.save(commit=False) -# contact_request.partner = partner -# contact_request.save() -# messages.success(request, ('<h3>Request sent</h3>' -# 'We will process your request as soon as possible.')) -# return redirect(partner.get_absolute_url()) -# context = { -# 'partner': partner, -# 'form': form -# } -# return render(request, 'partners/partner_request_contact.html', context) - - -# @permission_required('scipost.can_manage_SPB', return_403=True) -# def process_contact_requests(request): -# form = RequestContactForm(request.POST or None) - -# RequestContactModelFormSet = modelformset_factory(ContactRequest, ProcessRequestContactForm, -# formset=RequestContactFormSet, extra=0) -# formset = RequestContactModelFormSet(request.POST or None, -# queryset=ContactRequest.objects.awaiting_processing()) -# if formset.is_valid(): -# formset.process_requests(current_user=request.user) -# messages.success(request, 'Processing completed') -# return redirect(reverse('partners:process_contact_requests')) -# context = { -# 'form': form, -# 'formset': formset -# } -# return render(request, 'partners/process_contact_requests.html', context) - - - -########################### -# Prospective Partner Views -########################### - -# @permission_required('scipost.can_manage_SPB', return_403=True) -# def add_prospective_partner(request): -# form = ProspectivePartnerForm(request.POST or None) -# if form.is_valid(): -# pp = form.save() -# messages.success(request, 'Prospective Partner successfully added') -# return redirect(reverse('partners:add_prospartner_contact', -# kwargs={'prospartner_id': pp.id})) -# context = {'form': form} -# return render(request, 'partners/add_prospective_partner.html', context) - - -# @permission_required('scipost.can_manage_SPB', return_403=True) -# def add_prospartner_contact(request, prospartner_id): -# prospartner = get_object_or_404(ProspectivePartner, pk=prospartner_id) -# form = ProspectiveContactForm(request.POST or None, initial={'prospartner': prospartner}) -# if form.is_valid(): -# form.save() -# messages.success(request, 'Contact successfully added to Prospective Partner') -# return redirect(reverse('partners:dashboard')) -# context = {'form': form, 'prospartner': prospartner} -# return render(request, 'partners/add_prospartner_contact.html', context) - - -# @permission_required('scipost.can_email_prospartner_contact', return_403=True) -# @transaction.atomic -# def email_prospartner_contact(request, contact_id, mail=None): -# contact = get_object_or_404(ProspectiveContact, pk=contact_id) - -# suffix = '' -# if mail == 'followup': -# code = 'partners_followup_mail' -# suffix = ' (followup)' -# new_status = PROSPECTIVE_PARTNER_FOLLOWED_UP -# else: -# code = 'partners_initial_mail' -# new_status = PROSPECTIVE_PARTNER_APPROACHED -# mail_request = MailEditingSubView(request, mail_code=code, contact=contact) -# if mail_request.is_valid(): -# comments = 'Email{suffix} sent to {name}.'.format(suffix=suffix, name=contact) -# prospartnerevent = ProspectivePartnerEvent( -# prospartner=contact.prospartner, -# event=PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT, -# comments=comments, -# noted_on=timezone.now(), -# noted_by=request.user.contributor) -# prospartnerevent.save() -# if contact.prospartner.status in [PROSPECTIVE_PARTNER_REQUESTED, -# PROSPECTIVE_PARTNER_ADDED, -# PROSPECTIVE_PARTNER_APPROACHED]: -# contact.prospartner.status = new_status -# contact.prospartner.save() - -# messages.success(request, 'Email successfully sent.') -# mail_request.send() -# return redirect(reverse('partners:dashboard')) -# else: -# return mail_request.return_render() - - -# @permission_required('scipost.can_email_prospartner_contact', return_403=True) -# @transaction.atomic -# def email_prospartner_generic(request, prospartner_id, mail=None): -# prospartner = get_object_or_404(ProspectivePartner, pk=prospartner_id) - -# suffix = '' - -# if mail == 'followup': -# code = 'partners_followup_mail' -# suffix = ' (followup)' -# new_status = PROSPECTIVE_PARTNER_FOLLOWED_UP -# else: -# code = 'partners_initial_mail' -# new_status = PROSPECTIVE_PARTNER_APPROACHED -# mail_request = MailEditingSubView(request, mail_code=code) -# if mail_request.is_valid(): -# comments = 'Email{suffix} sent to {name}.'.format(suffix=suffix, -# name=mail_request.recipients_string) -# prospartnerevent = ProspectivePartnerEvent( -# prospartner=prospartner, -# event=PROSPECTIVE_PARTNER_EVENT_EMAIL_SENT, -# comments=comments, -# noted_on=timezone.now(), -# noted_by=request.user.contributor) -# prospartnerevent.save() -# if prospartner.status in [PROSPECTIVE_PARTNER_REQUESTED, -# PROSPECTIVE_PARTNER_ADDED, -# PROSPECTIVE_PARTNER_APPROACHED]: -# prospartner.status = new_status -# prospartner.save() - -# messages.success(request, 'Email successfully sent.') -# mail_request.send() -# return redirect(reverse('partners:dashboard')) -# else: -# return mail_request.return_render() - - -# @permission_required('scipost.can_manage_SPB', return_403=True) -# @transaction.atomic -# def add_prospartner_event(request, prospartner_id): -# prospartner = get_object_or_404(ProspectivePartner, pk=prospartner_id) -# if request.method == 'POST': -# ppevent_form = ProspectivePartnerEventForm(request.POST) -# if ppevent_form.is_valid(): -# ppevent = ppevent_form.save(commit=False) -# ppevent.prospartner = prospartner -# ppevent.noted_by = request.user.contributor -# ppevent.save() -# prospartner.update_status_from_event(ppevent.event) -# prospartner.save() -# return redirect(reverse('partners:dashboard')) -# else: -# errormessage = 'The form was invalidly filled.' -# return render(request, 'scipost/error.html', {'errormessage': errormessage}) -# errormessage = 'This view can only be posted to.' -# return render(request, 'scipost/error.html', {'errormessage': errormessage}) - - -############ -# Agreements -############ -# @permission_required('scipost.can_manage_SPB', return_403=True) -# def add_agreement(request): -# form = MembershipAgreementForm(request.POST or None, initial=request.GET) -# if request.POST and form.is_valid(): -# agreement = form.save(request.user) -# messages.success(request, 'Membership Agreement created.') -# return redirect(agreement.get_absolute_url()) -# context = { -# 'form': form -# } -# return render(request, 'partners/agreements_add.html', context) - - -# @permission_required('scipost.can_view_own_partner_details', return_403=True) -# def agreement_details(request, agreement_id): -# agreement = get_object_or_404(MembershipAgreement, id=agreement_id) -# context = {} - -# if request.user.has_perm('scipost.can_manage_SPB'): -# form = MembershipAgreementForm(request.POST or None, instance=agreement) - -# context['form'] = form -# if form.is_valid(): -# agreement = form.save(request.user) -# messages.success(request, 'Membership Agreement updated.') -# return redirect(agreement.get_absolute_url()) - -# context['agreement'] = agreement -# return render(request, 'partners/agreements_details.html', context) - - - -######### -# Account -######### -# def activate_account(request, activation_key): -# contact = get_object_or_404(Contact, user__is_active=False, -# activation_key=activation_key, -# user__email__icontains=request.GET.get('email', None)) - -# # TODO: Key Expires fallback -# form = ActivationForm(request.POST or None, instance=contact.user) -# if form.is_valid(): -# form.activate_user() -# messages.success(request, '<h3>Thank you for registration</h3>') -# return redirect(reverse('partners:dashboard')) -# context = { -# 'contact': contact, -# 'form': form -# } -# return render(request, 'partners/activate_account.html', context)