forked from CGM_Public/pretix_original
Allow to use custom domains for some but not all events (Z#23153875) (#4627)
* Allow to use custom domains for some but not all events * Update src/pretix/multidomain/urlreverse.py * Apply suggestions from code review Co-authored-by: Mira <weller@rami.io> * Logging for domain config changes --------- Co-authored-by: Mira <weller@rami.io>
This commit is contained in:
@@ -823,6 +823,9 @@ class Event(EventMixin, LoggedModel):
|
|||||||
self.save()
|
self.save()
|
||||||
self.log_action('pretix.object.cloned', data={'source': other.slug, 'source_id': other.pk})
|
self.log_action('pretix.object.cloned', data={'source': other.slug, 'source_id': other.pk})
|
||||||
|
|
||||||
|
if hasattr(other, 'alternative_domain_assignment'):
|
||||||
|
other.alternative_domain_assignment.domain.event_assignments.create(event=self)
|
||||||
|
|
||||||
if not self.all_sales_channels:
|
if not self.all_sales_channels:
|
||||||
self.limit_sales_channels.set(
|
self.limit_sales_channels.set(
|
||||||
self.organizer.sales_channels.filter(
|
self.organizer.sales_channels.filter(
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
# License for the specific language governing permissions and limitations under the License.
|
# License for the specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from urllib.parse import urlencode, urlparse
|
from urllib.parse import urlencode
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import pycountry
|
import pycountry
|
||||||
@@ -76,8 +76,10 @@ from pretix.control.forms import (
|
|||||||
)
|
)
|
||||||
from pretix.control.forms.widgets import Select2
|
from pretix.control.forms.widgets import Select2
|
||||||
from pretix.helpers.countries import CachedCountries
|
from pretix.helpers.countries import CachedCountries
|
||||||
from pretix.multidomain.models import KnownDomain
|
from pretix.multidomain.models import AlternativeDomainAssignment, KnownDomain
|
||||||
from pretix.multidomain.urlreverse import build_absolute_uri
|
from pretix.multidomain.urlreverse import (
|
||||||
|
build_absolute_uri, get_organizer_domain,
|
||||||
|
)
|
||||||
from pretix.plugins.banktransfer.payment import BankTransfer
|
from pretix.plugins.banktransfer.payment import BankTransfer
|
||||||
from pretix.presale.style import get_fonts
|
from pretix.presale.style import get_fonts
|
||||||
|
|
||||||
@@ -363,14 +365,9 @@ class EventUpdateForm(I18nModelForm):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.change_slug = kwargs.pop('change_slug', False)
|
self.change_slug = kwargs.pop('change_slug', False)
|
||||||
self.domain = kwargs.pop('domain', False)
|
|
||||||
|
|
||||||
kwargs.setdefault('initial', {})
|
kwargs.setdefault('initial', {})
|
||||||
self.instance = kwargs['instance']
|
self.instance = kwargs['instance']
|
||||||
if self.domain and self.instance:
|
|
||||||
initial_domain = self.instance.domains.first()
|
|
||||||
if initial_domain:
|
|
||||||
kwargs['initial'].setdefault('domain', initial_domain.domainname)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if not self.change_slug:
|
if not self.change_slug:
|
||||||
@@ -379,48 +376,54 @@ class EventUpdateForm(I18nModelForm):
|
|||||||
self.fields['location'].widget.attrs['placeholder'] = _(
|
self.fields['location'].widget.attrs['placeholder'] = _(
|
||||||
'Sample Conference Center\nHeidelberg, Germany'
|
'Sample Conference Center\nHeidelberg, Germany'
|
||||||
)
|
)
|
||||||
if self.domain:
|
|
||||||
|
try:
|
||||||
self.fields['domain'] = forms.CharField(
|
self.fields['domain'] = forms.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
label=_('Custom domain'),
|
label=_('Domain'),
|
||||||
|
initial=self.instance.domain.domainname,
|
||||||
|
required=False,
|
||||||
|
disabled=True,
|
||||||
|
help_text=_('You can configure this in your organizer settings.')
|
||||||
|
)
|
||||||
|
except KnownDomain.DoesNotExist:
|
||||||
|
domain = get_organizer_domain(self.instance.organizer)
|
||||||
|
try:
|
||||||
|
current_domain_assignment = self.instance.alternative_domain_assignment
|
||||||
|
except AlternativeDomainAssignment.DoesNotExist:
|
||||||
|
current_domain_assignment = None
|
||||||
|
self.fields['domain'] = forms.ChoiceField(
|
||||||
|
label=_('Domain'),
|
||||||
|
help_text=_('You can add more domains in your organizer account.'),
|
||||||
|
choices=[('', _('Same as organizer account') + (f" ({domain})" if domain else ""))] + [
|
||||||
|
(d.domainname, d.domainname) for d in self.instance.organizer.domains.filter(mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
],
|
||||||
|
initial=current_domain_assignment.domain_id if current_domain_assignment else "",
|
||||||
required=False,
|
required=False,
|
||||||
help_text=_('You need to configure the custom domain in the webserver beforehand.')
|
|
||||||
)
|
)
|
||||||
self.fields['limit_sales_channels'].queryset = self.event.organizer.sales_channels.all()
|
self.fields['limit_sales_channels'].queryset = self.event.organizer.sales_channels.all()
|
||||||
self.fields['limit_sales_channels'].widget = SalesChannelCheckboxSelectMultiple(self.event, attrs={
|
self.fields['limit_sales_channels'].widget = SalesChannelCheckboxSelectMultiple(self.event, attrs={
|
||||||
'data-inverse-dependency': '<[name$=all_sales_channels]',
|
'data-inverse-dependency': '<[name$=all_sales_channels]',
|
||||||
}, choices=self.fields['limit_sales_channels'].widget.choices)
|
}, choices=self.fields['limit_sales_channels'].widget.choices)
|
||||||
|
|
||||||
def clean_domain(self):
|
|
||||||
d = self.cleaned_data['domain']
|
|
||||||
if d:
|
|
||||||
if d == urlparse(settings.SITE_URL).hostname:
|
|
||||||
raise ValidationError(
|
|
||||||
_('You cannot choose the base domain of this installation.')
|
|
||||||
)
|
|
||||||
if KnownDomain.objects.filter(domainname=d).exclude(event=self.instance.pk).exists():
|
|
||||||
raise ValidationError(
|
|
||||||
_('This domain is already in use for a different event or organizer.')
|
|
||||||
)
|
|
||||||
return d
|
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
instance = super().save(commit)
|
instance = super().save(commit)
|
||||||
|
|
||||||
if self.domain:
|
try:
|
||||||
current_domain = instance.domains.first()
|
current_domain_assignment = instance.alternative_domain_assignment
|
||||||
if self.cleaned_data['domain']:
|
except AlternativeDomainAssignment.DoesNotExist:
|
||||||
if current_domain and current_domain.domainname != self.cleaned_data['domain']:
|
current_domain_assignment = None
|
||||||
current_domain.delete()
|
if self.cleaned_data['domain'] and not hasattr(instance, 'domain'):
|
||||||
KnownDomain.objects.create(
|
domain = self.instance.organizer.domains.get(mode=KnownDomain.MODE_ORG_ALT_DOMAIN, domainname=self.cleaned_data["domain"])
|
||||||
organizer=instance.organizer, event=instance, domainname=self.cleaned_data['domain']
|
AlternativeDomainAssignment.objects.update_or_create(
|
||||||
)
|
event=instance,
|
||||||
elif not current_domain:
|
defaults={
|
||||||
KnownDomain.objects.create(
|
"domain": domain,
|
||||||
organizer=instance.organizer, event=instance, domainname=self.cleaned_data['domain']
|
}
|
||||||
)
|
)
|
||||||
elif current_domain:
|
instance.cache.clear()
|
||||||
current_domain.delete()
|
elif current_domain_assignment:
|
||||||
|
current_domain_assignment.delete()
|
||||||
instance.cache.clear()
|
instance.cache.clear()
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|||||||
@@ -133,63 +133,108 @@ class OrganizerDeleteForm(forms.Form):
|
|||||||
class OrganizerUpdateForm(OrganizerForm):
|
class OrganizerUpdateForm(OrganizerForm):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.domain = kwargs.pop('domain', False)
|
|
||||||
self.change_slug = kwargs.pop('change_slug', False)
|
self.change_slug = kwargs.pop('change_slug', False)
|
||||||
kwargs.setdefault('initial', {})
|
kwargs.setdefault('initial', {})
|
||||||
self.instance = kwargs['instance']
|
self.instance = kwargs['instance']
|
||||||
if self.domain and self.instance:
|
|
||||||
initial_domain = self.instance.domains.filter(event__isnull=True).first()
|
|
||||||
if initial_domain:
|
|
||||||
kwargs['initial'].setdefault('domain', initial_domain.domainname)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if not self.change_slug:
|
if not self.change_slug:
|
||||||
self.fields['slug'].widget.attrs['readonly'] = 'readonly'
|
self.fields['slug'].widget.attrs['readonly'] = 'readonly'
|
||||||
if self.domain:
|
|
||||||
self.fields['domain'] = forms.CharField(
|
|
||||||
max_length=255,
|
|
||||||
label=_('Custom domain'),
|
|
||||||
required=False,
|
|
||||||
help_text=_('You need to configure the custom domain in the webserver beforehand.')
|
|
||||||
)
|
|
||||||
|
|
||||||
def clean_domain(self):
|
|
||||||
d = self.cleaned_data['domain']
|
|
||||||
if d:
|
|
||||||
if d == urlparse(settings.SITE_URL).hostname:
|
|
||||||
raise ValidationError(
|
|
||||||
_('You cannot choose the base domain of this installation.')
|
|
||||||
)
|
|
||||||
if KnownDomain.objects.filter(domainname=d).exclude(organizer=self.instance.pk,
|
|
||||||
event__isnull=True).exists():
|
|
||||||
raise ValidationError(
|
|
||||||
_('This domain is already in use for a different event or organizer.')
|
|
||||||
)
|
|
||||||
return d
|
|
||||||
|
|
||||||
def clean_slug(self):
|
def clean_slug(self):
|
||||||
if self.change_slug:
|
if self.change_slug:
|
||||||
return self.cleaned_data['slug']
|
return self.cleaned_data['slug']
|
||||||
return self.instance.slug
|
return self.instance.slug
|
||||||
|
|
||||||
def save(self, commit=True):
|
|
||||||
instance = super().save(commit)
|
|
||||||
|
|
||||||
if self.domain:
|
class KnownDomainForm(forms.ModelForm):
|
||||||
current_domain = instance.domains.filter(event__isnull=True).first()
|
class Meta:
|
||||||
if self.cleaned_data['domain']:
|
model = KnownDomain
|
||||||
if current_domain and current_domain.domainname != self.cleaned_data['domain']:
|
fields = ["domainname", "mode", "event"]
|
||||||
current_domain.delete()
|
field_classes = {
|
||||||
KnownDomain.objects.create(organizer=instance, domainname=self.cleaned_data['domain'])
|
"event": SafeModelChoiceField,
|
||||||
elif not current_domain:
|
}
|
||||||
KnownDomain.objects.create(organizer=instance, domainname=self.cleaned_data['domain'])
|
|
||||||
elif current_domain:
|
|
||||||
current_domain.delete()
|
|
||||||
instance.cache.clear()
|
|
||||||
for ev in instance.events.all():
|
|
||||||
ev.cache.clear()
|
|
||||||
|
|
||||||
return instance
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.organizer = kwargs.pop('organizer')
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields["event"].queryset = self.organizer.events.all()
|
||||||
|
if self.instance and self.instance.pk:
|
||||||
|
self.fields["domainname"].widget.attrs['readonly'] = 'readonly'
|
||||||
|
|
||||||
|
def clean_domainname(self):
|
||||||
|
if self.instance and self.instance.pk:
|
||||||
|
return self.instance.domainname
|
||||||
|
d = self.cleaned_data['domainname']
|
||||||
|
if d:
|
||||||
|
if d == urlparse(settings.SITE_URL).hostname:
|
||||||
|
raise ValidationError(
|
||||||
|
_('You cannot choose the base domain of this installation.')
|
||||||
|
)
|
||||||
|
if KnownDomain.objects.filter(domainname=d).exclude(organizer=self.instance.organizer).exists():
|
||||||
|
raise ValidationError(
|
||||||
|
_('This domain is already in use for a different event or organizer.')
|
||||||
|
)
|
||||||
|
return d
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
d = super().clean()
|
||||||
|
|
||||||
|
if d["mode"] == KnownDomain.MODE_ORG_DOMAIN and d["event"]:
|
||||||
|
raise ValidationError(
|
||||||
|
_("Do not choose an event for this mode.")
|
||||||
|
)
|
||||||
|
|
||||||
|
if d["mode"] == KnownDomain.MODE_ORG_ALT_DOMAIN and d["event"]:
|
||||||
|
raise ValidationError(
|
||||||
|
_("Do not choose an event for this mode. You can assign events to this domain in event settings.")
|
||||||
|
)
|
||||||
|
|
||||||
|
if d["mode"] == KnownDomain.MODE_EVENT_DOMAIN and not d["event"]:
|
||||||
|
raise ValidationError(
|
||||||
|
_("You need to choose an event.")
|
||||||
|
)
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
class BaseKnownDomainFormSet(forms.BaseInlineFormSet):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.organizer = kwargs.pop('organizer')
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def _construct_form(self, i, **kwargs):
|
||||||
|
kwargs['organizer'] = self.organizer
|
||||||
|
return super()._construct_form(i, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def empty_form(self):
|
||||||
|
form = self.form(
|
||||||
|
auto_id=self.auto_id,
|
||||||
|
prefix=self.add_prefix('__prefix__'),
|
||||||
|
empty_permitted=True,
|
||||||
|
use_required_attribute=False,
|
||||||
|
organizer=self.organizer,
|
||||||
|
)
|
||||||
|
self.add_fields(form, None)
|
||||||
|
return form
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
super().clean()
|
||||||
|
data = [f.cleaned_data for f in self.forms]
|
||||||
|
|
||||||
|
if len([d for d in data if d.get("mode") == KnownDomain.MODE_ORG_DOMAIN and not d.get("DELETE")]) > 1:
|
||||||
|
raise ValidationError(_("You may set only one organizer domain."))
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
KnownDomainFormset = inlineformset_factory(
|
||||||
|
Organizer, KnownDomain,
|
||||||
|
KnownDomainForm,
|
||||||
|
formset=BaseKnownDomainFormSet,
|
||||||
|
can_order=False, can_delete=True, extra=0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SafeOrderPositionChoiceField(forms.ModelChoiceField):
|
class SafeOrderPositionChoiceField(forms.ModelChoiceField):
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
{% bootstrap_field form.name layout="control" %}
|
{% bootstrap_field form.name layout="control" %}
|
||||||
{% bootstrap_field form.slug layout="control" %}
|
{% bootstrap_field form.slug layout="control" %}
|
||||||
{% if form.domain %}
|
{% if form.domain %}
|
||||||
{% bootstrap_field form.domain layout="control" %}
|
{% bootstrap_field form.domain layout="horizontal" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% bootstrap_field form.date_from layout="control" %}
|
{% bootstrap_field form.date_from layout="control" %}
|
||||||
{% bootstrap_field form.date_to layout="control" %}
|
{% bootstrap_field form.date_to layout="control" %}
|
||||||
|
|||||||
@@ -294,6 +294,71 @@
|
|||||||
<legend>{% trans "Invoices" %}</legend>
|
<legend>{% trans "Invoices" %}</legend>
|
||||||
{% bootstrap_field sform.invoice_regenerate_allowed layout="control" %}
|
{% bootstrap_field sform.invoice_regenerate_allowed layout="control" %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
{% if domain_formset %}
|
||||||
|
<fieldset>
|
||||||
|
<legend>{% trans "Domains" %}</legend>
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% trans "This dialog is intended for advanced users." %}
|
||||||
|
{% trans "The domain needs to be configured on your webserver before it can be used here." %}
|
||||||
|
</div>
|
||||||
|
<div class="formset" data-formset data-formset-prefix="{{ domain_formset.prefix }}">
|
||||||
|
{{ domain_formset.management_form }}
|
||||||
|
{% bootstrap_formset_errors domain_formset %}
|
||||||
|
<div data-formset-body>
|
||||||
|
{% for form in domain_formset %}
|
||||||
|
<div class="row formset-row" data-formset-form>
|
||||||
|
<div class="sr-only">
|
||||||
|
{{ form.id }}
|
||||||
|
{% bootstrap_field form.DELETE form_group_class="" layout="inline" %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
{% bootstrap_field form.domainname layout='' form_group_class="" %}
|
||||||
|
{% bootstrap_form_errors form %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
{% bootstrap_field form.mode layout='' form_group_class="" %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
{% bootstrap_field form.event layout='' form_group_class="" %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2 text-right flip">
|
||||||
|
<label aria-hidden="true"> </label><br>
|
||||||
|
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||||
|
<i class="fa fa-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<script type="form-template" data-formset-empty-form>
|
||||||
|
{% escapescript %}
|
||||||
|
<div class="row formset-row" data-formset-form>
|
||||||
|
<div class="sr-only">
|
||||||
|
{{ domain_formset.empty_form.id }}
|
||||||
|
{% bootstrap_field domain_formset.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
{% bootstrap_field domain_formset.empty_form.domainname layout='' form_group_class="" %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
{% bootstrap_field domain_formset.empty_form.mode layout='' form_group_class="" %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
{% bootstrap_field domain_formset.empty_form.event layout='' form_group_class="" %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2 text-right flip">
|
||||||
|
<label aria-hidden="true"> </label><br>
|
||||||
|
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||||
|
<i class="fa fa-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endescapescript %}
|
||||||
|
</script>
|
||||||
|
<p>
|
||||||
|
<button type="button" class="btn btn-default" data-formset-add>
|
||||||
|
<i class="fa fa-plus"></i> {% trans "Add domain" %}</button>
|
||||||
|
</p>
|
||||||
|
</fieldset>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group submit-group">
|
<div class="form-group submit-group">
|
||||||
<button type="submit" class="btn btn-primary btn-save">
|
<button type="submit" class="btn btn-primary btn-save">
|
||||||
|
|||||||
@@ -239,7 +239,6 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
|||||||
kwargs = super().get_form_kwargs()
|
kwargs = super().get_form_kwargs()
|
||||||
if self.request.user.has_active_staff_session(self.request.session.session_key):
|
if self.request.user.has_active_staff_session(self.request.session.session_key):
|
||||||
kwargs['change_slug'] = True
|
kwargs['change_slug'] = True
|
||||||
kwargs['domain'] = True
|
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
|||||||
@@ -104,11 +104,11 @@ from pretix.control.forms.organizer import (
|
|||||||
CustomerCreateForm, CustomerUpdateForm, DeviceBulkEditForm, DeviceForm,
|
CustomerCreateForm, CustomerUpdateForm, DeviceBulkEditForm, DeviceForm,
|
||||||
EventMetaPropertyAllowedValueFormSet, EventMetaPropertyForm, GateForm,
|
EventMetaPropertyAllowedValueFormSet, EventMetaPropertyForm, GateForm,
|
||||||
GiftCardAcceptanceInviteForm, GiftCardCreateForm, GiftCardUpdateForm,
|
GiftCardAcceptanceInviteForm, GiftCardCreateForm, GiftCardUpdateForm,
|
||||||
MailSettingsForm, MembershipTypeForm, MembershipUpdateForm,
|
KnownDomainFormset, MailSettingsForm, MembershipTypeForm,
|
||||||
OrganizerDeleteForm, OrganizerFooterLinkFormset, OrganizerForm,
|
MembershipUpdateForm, OrganizerDeleteForm, OrganizerFooterLinkFormset,
|
||||||
OrganizerSettingsForm, OrganizerUpdateForm, ReusableMediumCreateForm,
|
OrganizerForm, OrganizerSettingsForm, OrganizerUpdateForm,
|
||||||
ReusableMediumUpdateForm, SalesChannelForm, SSOClientForm, SSOProviderForm,
|
ReusableMediumCreateForm, ReusableMediumUpdateForm, SalesChannelForm,
|
||||||
TeamForm, WebHookForm,
|
SSOClientForm, SSOProviderForm, TeamForm, WebHookForm,
|
||||||
)
|
)
|
||||||
from pretix.control.forms.rrule import RRuleForm
|
from pretix.control.forms.rrule import RRuleForm
|
||||||
from pretix.control.logdisplay import OVERVIEW_BANLIST
|
from pretix.control.logdisplay import OVERVIEW_BANLIST
|
||||||
@@ -447,6 +447,10 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
|
|||||||
def get_object(self, queryset=None) -> Organizer:
|
def get_object(self, queryset=None) -> Organizer:
|
||||||
return self.object
|
return self.object
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def domain_config(self):
|
||||||
|
return self.request.user.has_active_staff_session(self.request.session.session_key)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def sform(self):
|
def sform(self):
|
||||||
return OrganizerSettingsForm(
|
return OrganizerSettingsForm(
|
||||||
@@ -461,6 +465,8 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
|
|||||||
context = super().get_context_data(*args, **kwargs)
|
context = super().get_context_data(*args, **kwargs)
|
||||||
context['sform'] = self.sform
|
context['sform'] = self.sform
|
||||||
context['footer_links_formset'] = self.footer_links_formset
|
context['footer_links_formset'] = self.footer_links_formset
|
||||||
|
if self.domain_config:
|
||||||
|
context['domain_formset'] = self.domain_formset
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
@@ -483,6 +489,8 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
|
|||||||
self.request.organizer.log_action('pretix.organizer.footerlinks.changed', user=self.request.user, data={
|
self.request.organizer.log_action('pretix.organizer.footerlinks.changed', user=self.request.user, data={
|
||||||
'data': self.footer_links_formset.cleaned_data
|
'data': self.footer_links_formset.cleaned_data
|
||||||
})
|
})
|
||||||
|
if self.domain_config and self.domain_formset.has_changed():
|
||||||
|
self._save_domain_config()
|
||||||
if form.has_changed():
|
if form.has_changed():
|
||||||
self.request.organizer.log_action(
|
self.request.organizer.log_action(
|
||||||
'pretix.organizer.changed',
|
'pretix.organizer.changed',
|
||||||
@@ -493,10 +501,22 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
|
|||||||
messages.success(self.request, _('Your changes have been saved.'))
|
messages.success(self.request, _('Your changes have been saved.'))
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
def _save_domain_config(self):
|
||||||
|
for form in self.domain_formset.initial_forms:
|
||||||
|
if form.instance.pk and form.has_changed():
|
||||||
|
self.object.domains.get(pk=form.instance.pk).log_delete(self.request.user)
|
||||||
|
self.domain_formset.save()
|
||||||
|
for new_obj in self.domain_formset.new_objects:
|
||||||
|
new_obj.log_create(self.request.user)
|
||||||
|
for ch_obj, form in self.domain_formset.changed_objects:
|
||||||
|
ch_obj.log_create(self.request.user)
|
||||||
|
self.request.organizer.cache.clear()
|
||||||
|
for ev in self.request.organizer.events.all():
|
||||||
|
ev.cache.clear()
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
kwargs = super().get_form_kwargs()
|
kwargs = super().get_form_kwargs()
|
||||||
if self.request.user.has_active_staff_session(self.request.session.session_key):
|
if self.request.user.has_active_staff_session(self.request.session.session_key):
|
||||||
kwargs['domain'] = True
|
|
||||||
kwargs['change_slug'] = True
|
kwargs['change_slug'] = True
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
@@ -508,7 +528,7 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
|
|||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
if form.is_valid() and self.sform.is_valid() and self.footer_links_formset.is_valid():
|
if form.is_valid() and self.sform.is_valid() and self.footer_links_formset.is_valid() and (not self.domain_config or self.domain_formset.is_valid()):
|
||||||
return self.form_valid(form)
|
return self.form_valid(form)
|
||||||
else:
|
else:
|
||||||
return self.form_invalid(form)
|
return self.form_invalid(form)
|
||||||
@@ -519,6 +539,11 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
|
|||||||
organizer=self.object,
|
organizer=self.object,
|
||||||
prefix="footer-links", instance=self.object)
|
prefix="footer-links", instance=self.object)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def domain_formset(self):
|
||||||
|
return KnownDomainFormset(self.request.POST if self.request.method == "POST" else None, prefix="domains",
|
||||||
|
instance=self.object, organizer=self.object)
|
||||||
|
|
||||||
def save_footer_links_formset(self, obj):
|
def save_footer_links_formset(self, obj):
|
||||||
self.footer_links_formset.save()
|
self.footer_links_formset.save()
|
||||||
|
|
||||||
|
|||||||
@@ -80,28 +80,32 @@ class MultiDomainMiddleware(MiddlewareMixin):
|
|||||||
request.port = int(port) if port else None
|
request.port = int(port) if port else None
|
||||||
request.host = domain
|
request.host = domain
|
||||||
if domain == default_domain:
|
if domain == default_domain:
|
||||||
|
request.domain_mode = "system"
|
||||||
request.urlconf = "pretix.multidomain.maindomain_urlconf"
|
request.urlconf = "pretix.multidomain.maindomain_urlconf"
|
||||||
elif domain:
|
elif domain:
|
||||||
cached = cache.get('pretix_multidomain_instance_{}'.format(domain))
|
cached = cache.get('pretix_multidomain_instances_{}'.format(domain))
|
||||||
|
|
||||||
if cached is None:
|
if cached is None:
|
||||||
try:
|
try:
|
||||||
kd = KnownDomain.objects.select_related('organizer', 'event').get(domainname=domain) # noqa
|
kd = KnownDomain.objects.select_related('organizer', 'event').get(domainname=domain) # noqa
|
||||||
orga = kd.organizer
|
orga = kd.organizer
|
||||||
event = kd.event
|
event = kd.event
|
||||||
|
mode = kd.mode
|
||||||
except KnownDomain.DoesNotExist:
|
except KnownDomain.DoesNotExist:
|
||||||
orga = False
|
orga = False
|
||||||
event = False
|
event = False
|
||||||
|
mode = "system"
|
||||||
cache.set(
|
cache.set(
|
||||||
'pretix_multidomain_instance_{}'.format(domain),
|
'pretix_multidomain_instances_{}'.format(domain),
|
||||||
(orga.pk if orga else None, event.pk if event else None),
|
(orga.pk if orga else None, event.pk if event else None, mode),
|
||||||
3600
|
3600
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
orga, event = cached
|
orga, event, mode = cached
|
||||||
|
|
||||||
if event:
|
if mode == KnownDomain.MODE_EVENT_DOMAIN:
|
||||||
request.event_domain = True
|
request.event_domain = True
|
||||||
|
request.domain_mode = KnownDomain.MODE_EVENT_DOMAIN
|
||||||
if isinstance(event, Event):
|
if isinstance(event, Event):
|
||||||
request.organizer = orga
|
request.organizer = orga
|
||||||
request.event = event
|
request.event = event
|
||||||
@@ -110,11 +114,18 @@ class MultiDomainMiddleware(MiddlewareMixin):
|
|||||||
request.event = Event.objects.select_related('organizer').get(pk=event)
|
request.event = Event.objects.select_related('organizer').get(pk=event)
|
||||||
request.organizer = request.event.organizer
|
request.organizer = request.event.organizer
|
||||||
request.urlconf = "pretix.multidomain.event_domain_urlconf"
|
request.urlconf = "pretix.multidomain.event_domain_urlconf"
|
||||||
elif orga:
|
elif mode == KnownDomain.MODE_ORG_ALT_DOMAIN:
|
||||||
request.organizer_domain = True
|
request.organizer_domain = True
|
||||||
|
request.domain_mode = KnownDomain.MODE_ORG_ALT_DOMAIN
|
||||||
|
request.organizer = orga if isinstance(orga, Organizer) else Organizer.objects.get(pk=orga)
|
||||||
|
request.urlconf = "pretix.multidomain.organizer_alternative_domain_urlconf"
|
||||||
|
elif mode == KnownDomain.MODE_ORG_DOMAIN:
|
||||||
|
request.organizer_domain = True
|
||||||
|
request.domain_mode = KnownDomain.MODE_ORG_DOMAIN
|
||||||
request.organizer = orga if isinstance(orga, Organizer) else Organizer.objects.get(pk=orga)
|
request.organizer = orga if isinstance(orga, Organizer) else Organizer.objects.get(pk=orga)
|
||||||
request.urlconf = "pretix.multidomain.organizer_domain_urlconf"
|
request.urlconf = "pretix.multidomain.organizer_domain_urlconf"
|
||||||
elif settings.DEBUG or domain in LOCAL_HOST_NAMES:
|
elif settings.DEBUG or domain in LOCAL_HOST_NAMES:
|
||||||
|
request.domain_mode = "system"
|
||||||
request.urlconf = "pretix.multidomain.maindomain_urlconf"
|
request.urlconf = "pretix.multidomain.maindomain_urlconf"
|
||||||
else:
|
else:
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
|
|||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
# Generated by Django 4.2.16 on 2024-11-12 10:46
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("pretixbase", "0273_remove_checkinlist_auto_checkin_sales_channels"),
|
||||||
|
("pretixmultidomain", "0002_knowndomain_event"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="AlternativeDomainAssignment",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True, primary_key=True, serialize=False
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="knowndomain",
|
||||||
|
name="mode",
|
||||||
|
field=models.CharField(default="organizer", max_length=255),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="knowndomain",
|
||||||
|
name="event",
|
||||||
|
field=models.OneToOneField(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="domain",
|
||||||
|
to="pretixbase.event",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.RunSQL(
|
||||||
|
sql="UPDATE pretixmultidomain_knowndomain SET mode = 'event' WHERE event_id IS NOT NULL",
|
||||||
|
reverse_sql=migrations.RunSQL.noop,
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name="knowndomain",
|
||||||
|
constraint=models.UniqueConstraint(
|
||||||
|
condition=models.Q(("mode", "organizer")),
|
||||||
|
fields=("organizer",),
|
||||||
|
name="unique_organizer_domain",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="alternativedomainassignment",
|
||||||
|
name="domain",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="event_assignments",
|
||||||
|
to="pretixmultidomain.knowndomain",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="alternativedomainassignment",
|
||||||
|
name="event",
|
||||||
|
field=models.OneToOneField(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="alternative_domain_assignment",
|
||||||
|
to="pretixbase.event",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#
|
#
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
@@ -28,39 +29,134 @@ from pretix.base.models import Event, Organizer
|
|||||||
|
|
||||||
|
|
||||||
class KnownDomain(models.Model):
|
class KnownDomain(models.Model):
|
||||||
domainname = models.CharField(max_length=255, primary_key=True)
|
MODE_ORG_DOMAIN = "organizer"
|
||||||
organizer = models.ForeignKey(Organizer, blank=True, null=True, related_name='domains', on_delete=models.CASCADE)
|
MODE_ORG_ALT_DOMAIN = "organizer_alternative"
|
||||||
event = models.ForeignKey(Event, blank=True, null=True, related_name='domains', on_delete=models.PROTECT)
|
MODE_EVENT_DOMAIN = "event"
|
||||||
|
MODES = (
|
||||||
|
(MODE_ORG_DOMAIN, _("Organizer domain")),
|
||||||
|
(MODE_ORG_ALT_DOMAIN, _("Alternative organizer domain for a set of events")),
|
||||||
|
(MODE_EVENT_DOMAIN, _("Event domain")),
|
||||||
|
)
|
||||||
|
|
||||||
|
domainname = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
primary_key=True,
|
||||||
|
verbose_name=_("Domain name"),
|
||||||
|
)
|
||||||
|
mode = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
choices=MODES,
|
||||||
|
default=MODE_ORG_DOMAIN,
|
||||||
|
verbose_name=_("Mode"),
|
||||||
|
)
|
||||||
|
organizer = models.ForeignKey(
|
||||||
|
Organizer,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name='domains',
|
||||||
|
on_delete=models.CASCADE
|
||||||
|
)
|
||||||
|
event = models.OneToOneField(
|
||||||
|
Event,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name='domain',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
verbose_name=_("Event"),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Known domain")
|
verbose_name = _("Known domain")
|
||||||
verbose_name_plural = _("Known domains")
|
verbose_name_plural = _("Known domains")
|
||||||
|
constraints = [
|
||||||
|
models.UniqueConstraint(
|
||||||
|
fields=("organizer",),
|
||||||
|
name="unique_organizer_domain",
|
||||||
|
condition=Q(mode="organizer"),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
ordering = ("-mode", "domainname")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.domainname
|
return self.domainname
|
||||||
|
|
||||||
@scopes_disabled()
|
@scopes_disabled()
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
if self.event:
|
||||||
|
self.mode = KnownDomain.MODE_EVENT_DOMAIN
|
||||||
|
elif self.mode == KnownDomain.MODE_EVENT_DOMAIN:
|
||||||
|
raise ValueError("Event domain needs event")
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
if self.event:
|
if self.event:
|
||||||
self.event.get_cache().clear()
|
self.event.get_cache().clear()
|
||||||
|
try:
|
||||||
|
self.event.alternative_domain_assignment.delete()
|
||||||
|
except AlternativeDomainAssignment.DoesNotExist:
|
||||||
|
pass
|
||||||
elif self.organizer:
|
elif self.organizer:
|
||||||
self.organizer.get_cache().clear()
|
self.organizer.get_cache().clear()
|
||||||
for event in self.organizer.events.all():
|
for event in self.organizer.events.all():
|
||||||
event.get_cache().clear()
|
event.get_cache().clear()
|
||||||
cache.delete('pretix_multidomain_organizer_{}'.format(self.domainname))
|
cache.delete('pretix_multidomain_organizer_{}'.format(self.domainname))
|
||||||
cache.delete('pretix_multidomain_instance_{}'.format(self.domainname))
|
cache.delete('pretix_multidomain_instances_{}'.format(self.domainname))
|
||||||
cache.delete('pretix_multidomain_event_{}'.format(self.domainname))
|
cache.delete('pretix_multidomain_event_{}'.format(self.domainname))
|
||||||
|
|
||||||
@scopes_disabled()
|
@scopes_disabled()
|
||||||
def delete(self, *args, **kwargs):
|
def delete(self, *args, **kwargs):
|
||||||
if self.event:
|
if self.event:
|
||||||
self.event.get_cache().clear()
|
self.event.cache.clear()
|
||||||
elif self.organizer:
|
elif self.organizer:
|
||||||
self.organizer.get_cache().clear()
|
self.organizer.cache.clear()
|
||||||
for event in self.organizer.events.all():
|
for event in self.organizer.events.all():
|
||||||
event.get_cache().clear()
|
event.cache.clear()
|
||||||
cache.delete('pretix_multidomain_organizer_{}'.format(self.domainname))
|
cache.delete('pretix_multidomain_organizer_{}'.format(self.domainname))
|
||||||
cache.delete('pretix_multidomain_instance_{}'.format(self.domainname))
|
cache.delete('pretix_multidomain_instances_{}'.format(self.domainname))
|
||||||
cache.delete('pretix_multidomain_event_{}'.format(self.domainname))
|
cache.delete('pretix_multidomain_event_{}'.format(self.domainname))
|
||||||
super().delete(*args, **kwargs)
|
super().delete(*args, **kwargs)
|
||||||
|
|
||||||
|
def _log_domain_action(self, user, data):
|
||||||
|
if self.event:
|
||||||
|
self.event.log_action(
|
||||||
|
'pretix.event.settings',
|
||||||
|
user=user,
|
||||||
|
data=data
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.organizer.log_action(
|
||||||
|
'pretix.organizer.settings',
|
||||||
|
user=user,
|
||||||
|
data=data
|
||||||
|
)
|
||||||
|
|
||||||
|
def log_create(self, user):
|
||||||
|
self._log_domain_action(user, {'add_alt_domain': self.domainname} if self.mode == KnownDomain.MODE_ORG_ALT_DOMAIN else {'domain': self.domainname})
|
||||||
|
|
||||||
|
def log_delete(self, user):
|
||||||
|
self._log_domain_action(user, {'remove_alt_domain': self.domainname} if self.mode == KnownDomain.MODE_ORG_ALT_DOMAIN else {'domain': None})
|
||||||
|
|
||||||
|
|
||||||
|
class AlternativeDomainAssignment(models.Model):
|
||||||
|
domain = models.ForeignKey(
|
||||||
|
KnownDomain,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="event_assignments",
|
||||||
|
)
|
||||||
|
event = models.OneToOneField(
|
||||||
|
Event,
|
||||||
|
related_name="alternative_domain_assignment",
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
)
|
||||||
|
|
||||||
|
@scopes_disabled()
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
self.event.cache.clear()
|
||||||
|
cache.delete('pretix_multidomain_instances_{}'.format(self.domain_id))
|
||||||
|
cache.delete('pretix_multidomain_event_{}'.format(self.domain_id))
|
||||||
|
|
||||||
|
@scopes_disabled()
|
||||||
|
def delete(self, *args, **kwargs):
|
||||||
|
self.event.cache.clear()
|
||||||
|
cache.delete('pretix_multidomain_instances_{}'.format(self.domain_id))
|
||||||
|
cache.delete('pretix_multidomain_event_{}'.format(self.domain_id))
|
||||||
|
super().delete(*args, **kwargs)
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#
|
||||||
|
# This file is part of pretix (Community Edition).
|
||||||
|
#
|
||||||
|
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||||
|
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||||
|
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||||
|
#
|
||||||
|
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||||
|
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||||
|
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||||
|
# this file, see <https://pretix.eu/about/en/license>.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||||
|
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||||
|
# <https://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
import importlib.util
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
|
from django.urls import include, re_path
|
||||||
|
|
||||||
|
from pretix.multidomain.plugin_handler import plugin_event_urls
|
||||||
|
from pretix.presale.urls import event_patterns, locale_patterns
|
||||||
|
from pretix.presale.views import organizer
|
||||||
|
from pretix.urls import common_patterns
|
||||||
|
|
||||||
|
presale_patterns = [
|
||||||
|
re_path(r'', include((locale_patterns + [
|
||||||
|
re_path(r'^$', organizer.RedirectToOrganizerIndex.as_view(), name='organizer.alt.index'),
|
||||||
|
re_path(r'^(?P<event>[^/]+)/', include(event_patterns)),
|
||||||
|
], 'presale')))
|
||||||
|
]
|
||||||
|
|
||||||
|
raw_plugin_patterns = []
|
||||||
|
for app in apps.get_app_configs():
|
||||||
|
if hasattr(app, 'PretixPluginMeta'):
|
||||||
|
if importlib.util.find_spec(app.name + '.urls'):
|
||||||
|
urlmod = importlib.import_module(app.name + '.urls')
|
||||||
|
if hasattr(urlmod, 'event_patterns'):
|
||||||
|
patterns = plugin_event_urls(urlmod.event_patterns, plugin=app.name)
|
||||||
|
raw_plugin_patterns.append(
|
||||||
|
re_path(r'^(?P<event>[^/]+)/', include((patterns, app.label)))
|
||||||
|
)
|
||||||
|
if hasattr(urlmod, 'organizer_patterns'):
|
||||||
|
patterns = plugin_event_urls(urlmod.organizer_patterns, plugin=app.name)
|
||||||
|
raw_plugin_patterns.append(
|
||||||
|
re_path(r'', include((patterns, app.label)))
|
||||||
|
)
|
||||||
|
|
||||||
|
plugin_patterns = [
|
||||||
|
re_path(r'', include((raw_plugin_patterns, 'plugins')))
|
||||||
|
]
|
||||||
|
|
||||||
|
# The presale namespace comes last, because it contains a wildcard catch
|
||||||
|
urlpatterns = common_patterns + plugin_patterns + presale_patterns
|
||||||
|
|
||||||
|
handler404 = 'pretix.base.views.errors.page_not_found'
|
||||||
|
handler500 = 'pretix.base.views.errors.server_error'
|
||||||
@@ -43,28 +43,33 @@ from pretix.base.models import Event, Organizer
|
|||||||
from .models import KnownDomain
|
from .models import KnownDomain
|
||||||
|
|
||||||
|
|
||||||
def get_event_domain(event, fallback=False, return_info=False):
|
def get_event_domain(event, fallback=False, return_mode=False):
|
||||||
assert isinstance(event, Event)
|
assert isinstance(event, Event)
|
||||||
if not event.pk:
|
if not event.pk:
|
||||||
# Can happen on the "event deleted" response
|
# Can happen on the "event deleted" response
|
||||||
return (None, None) if return_info else None
|
return (None, None) if return_mode else None
|
||||||
suffix = ('_fallback' if fallback else '') + ('_info' if return_info else '')
|
suffix = ('_fallback' if fallback else '') + ('_mode' if return_mode else '')
|
||||||
domain = getattr(event, '_cached_domain' + suffix, None) or event.cache.get('domain' + suffix)
|
domain = getattr(event, '_cached_domain' + suffix, None) or event.cache.get('domain' + suffix)
|
||||||
if domain is None:
|
if domain is None:
|
||||||
domain = None, None
|
domain = None, None
|
||||||
if fallback:
|
if hasattr(event, 'alternative_domain_assignment'):
|
||||||
|
domain = event.alternative_domain_assignment.domain_id, KnownDomain.MODE_ORG_ALT_DOMAIN
|
||||||
|
elif fallback:
|
||||||
domains = KnownDomain.objects.filter(
|
domains = KnownDomain.objects.filter(
|
||||||
Q(event=event) | Q(organizer_id=event.organizer_id, event__isnull=True)
|
Q(event=event, mode=KnownDomain.MODE_EVENT_DOMAIN) |
|
||||||
|
Q(organizer_id=event.organizer_id, event__isnull=True, mode=KnownDomain.MODE_ORG_DOMAIN)
|
||||||
)
|
)
|
||||||
domains_event = [d for d in domains if d.event_id == event.pk]
|
domains_event = [d for d in domains if d.event_id == event.pk]
|
||||||
domains_org = [d for d in domains if not d.event_id]
|
domains_org = [d for d in domains if not d.event_id]
|
||||||
if domains_event:
|
if domains_event:
|
||||||
domain = domains_event[0].domainname, "event"
|
domain = domains_event[0].domainname, KnownDomain.MODE_EVENT_DOMAIN
|
||||||
elif domains_org:
|
elif domains_org:
|
||||||
domain = domains_org[0].domainname, "organizer"
|
domain = domains_org[0].domainname, KnownDomain.MODE_ORG_DOMAIN
|
||||||
else:
|
else:
|
||||||
domains = event.domains.all()
|
try:
|
||||||
domain = domains[0].domainname if domains else None, "event"
|
domain = event.domain.domainname, KnownDomain.MODE_EVENT_DOMAIN
|
||||||
|
except KnownDomain.DoesNotExist:
|
||||||
|
domain = None, None
|
||||||
event.cache.set('domain' + suffix, domain or 'none')
|
event.cache.set('domain' + suffix, domain or 'none')
|
||||||
setattr(event, '_cached_domain' + suffix, domain or 'none')
|
setattr(event, '_cached_domain' + suffix, domain or 'none')
|
||||||
elif domain == 'none':
|
elif domain == 'none':
|
||||||
@@ -72,7 +77,7 @@ def get_event_domain(event, fallback=False, return_info=False):
|
|||||||
domain = None, None
|
domain = None, None
|
||||||
else:
|
else:
|
||||||
setattr(event, '_cached_domain' + suffix, domain)
|
setattr(event, '_cached_domain' + suffix, domain)
|
||||||
return domain if return_info or not isinstance(domain, tuple) else domain[0]
|
return domain if return_mode else domain[0]
|
||||||
|
|
||||||
|
|
||||||
def get_organizer_domain(organizer):
|
def get_organizer_domain(organizer):
|
||||||
@@ -81,7 +86,7 @@ def get_organizer_domain(organizer):
|
|||||||
return None
|
return None
|
||||||
domain = getattr(organizer, '_cached_domain', None) or organizer.cache.get('domain')
|
domain = getattr(organizer, '_cached_domain', None) or organizer.cache.get('domain')
|
||||||
if domain is None:
|
if domain is None:
|
||||||
domains = organizer.domains.filter(event__isnull=True)
|
domains = organizer.domains.filter(event__isnull=True, mode=KnownDomain.MODE_ORG_DOMAIN)
|
||||||
domain = domains[0].domainname if domains else None
|
domain = domains[0].domainname if domains else None
|
||||||
organizer.cache.set('domain', domain or 'none')
|
organizer.cache.set('domain', domain or 'none')
|
||||||
organizer._cached_domain = domain or 'none'
|
organizer._cached_domain = domain or 'none'
|
||||||
@@ -131,7 +136,8 @@ def eventreverse(obj, name, kwargs=None):
|
|||||||
:returns: An absolute or relative URL as a string
|
:returns: An absolute or relative URL as a string
|
||||||
"""
|
"""
|
||||||
from pretix.multidomain import (
|
from pretix.multidomain import (
|
||||||
event_domain_urlconf, maindomain_urlconf, organizer_domain_urlconf,
|
event_domain_urlconf, maindomain_urlconf,
|
||||||
|
organizer_alternative_domain_urlconf, organizer_domain_urlconf,
|
||||||
)
|
)
|
||||||
|
|
||||||
c = None
|
c = None
|
||||||
@@ -153,17 +159,24 @@ def eventreverse(obj, name, kwargs=None):
|
|||||||
raise TypeError('obj should be Event or Organizer')
|
raise TypeError('obj should be Event or Organizer')
|
||||||
|
|
||||||
if event:
|
if event:
|
||||||
domain, domaintype = get_event_domain(obj, fallback=True, return_info=True)
|
domain, domaintype = get_event_domain(obj, fallback=True, return_mode=True)
|
||||||
else:
|
else:
|
||||||
domain, domaintype = get_organizer_domain(organizer), "organizer"
|
domain, domaintype = get_organizer_domain(organizer), KnownDomain.MODE_ORG_DOMAIN
|
||||||
|
|
||||||
if domain:
|
if domain:
|
||||||
if domaintype == "event" and 'event' in kwargs:
|
if domaintype == KnownDomain.MODE_EVENT_DOMAIN and 'event' in kwargs:
|
||||||
del kwargs['event']
|
del kwargs['event']
|
||||||
if 'organizer' in kwargs:
|
if 'organizer' in kwargs:
|
||||||
del kwargs['organizer']
|
del kwargs['organizer']
|
||||||
|
|
||||||
path = reverse(name, kwargs=kwargs, urlconf=event_domain_urlconf if domaintype == "event" else organizer_domain_urlconf)
|
if domaintype == KnownDomain.MODE_EVENT_DOMAIN:
|
||||||
|
urlconf = event_domain_urlconf
|
||||||
|
elif domaintype == KnownDomain.MODE_ORG_ALT_DOMAIN:
|
||||||
|
urlconf = organizer_alternative_domain_urlconf
|
||||||
|
else:
|
||||||
|
urlconf = organizer_domain_urlconf
|
||||||
|
|
||||||
|
path = reverse(name, kwargs=kwargs, urlconf=urlconf)
|
||||||
siteurlsplit = urlsplit(settings.SITE_URL)
|
siteurlsplit = urlsplit(settings.SITE_URL)
|
||||||
if siteurlsplit.port and siteurlsplit.port not in (80, 443):
|
if siteurlsplit.port and siteurlsplit.port not in (80, 443):
|
||||||
domain = '%s:%d' % (domain, siteurlsplit.port)
|
domain = '%s:%d' % (domain, siteurlsplit.port)
|
||||||
|
|||||||
+27
-10
@@ -57,8 +57,9 @@ from pretix.base.middleware import LocaleMiddleware
|
|||||||
from pretix.base.models import Customer, Event, Organizer
|
from pretix.base.models import Customer, Event, Organizer
|
||||||
from pretix.base.timemachine import time_machine_now_assigned_from_request
|
from pretix.base.timemachine import time_machine_now_assigned_from_request
|
||||||
from pretix.helpers.http import redirect_to_url
|
from pretix.helpers.http import redirect_to_url
|
||||||
|
from pretix.multidomain.models import KnownDomain
|
||||||
from pretix.multidomain.urlreverse import (
|
from pretix.multidomain.urlreverse import (
|
||||||
get_event_domain, get_organizer_domain,
|
build_absolute_uri, get_event_domain, get_organizer_domain,
|
||||||
)
|
)
|
||||||
from pretix.presale.signals import process_request, process_response
|
from pretix.presale.signals import process_request, process_response
|
||||||
|
|
||||||
@@ -134,7 +135,7 @@ def update_customer_session_auth_hash(request, customer):
|
|||||||
|
|
||||||
|
|
||||||
def add_customer_to_request(request):
|
def add_customer_to_request(request):
|
||||||
if 'cross_domain_customer_auth' in request.GET and request.event_domain:
|
if 'cross_domain_customer_auth' in request.GET and request.domain_mode in (KnownDomain.MODE_EVENT_DOMAIN, KnownDomain.MODE_ORG_ALT_DOMAIN):
|
||||||
# The user is logged in on the main domain and now wants to take their session
|
# The user is logged in on the main domain and now wants to take their session
|
||||||
# to a event-specific domain. We validate the one time token received via a
|
# to a event-specific domain. We validate the one time token received via a
|
||||||
# query parameter and make sure we invalidate it right away. Then, we look up
|
# query parameter and make sure we invalidate it right away. Then, we look up
|
||||||
@@ -258,11 +259,13 @@ def _detect_event(request, require_live=True, require_plugin=None):
|
|||||||
|
|
||||||
url = resolve(request.path_info)
|
url = resolve(request.path_info)
|
||||||
|
|
||||||
|
request_domain_mode = getattr(request, 'domain_mode', 'system')
|
||||||
|
print("Mode", request_domain_mode)
|
||||||
try:
|
try:
|
||||||
if hasattr(request, 'event_domain'):
|
if request_domain_mode == KnownDomain.MODE_EVENT_DOMAIN:
|
||||||
# We are on an event's custom domain
|
# We are on an event's custom domain
|
||||||
pass
|
pass
|
||||||
elif hasattr(request, 'organizer_domain'):
|
elif request_domain_mode in (KnownDomain.MODE_ORG_DOMAIN, KnownDomain.MODE_ORG_ALT_DOMAIN):
|
||||||
# We are on an organizer's custom domain
|
# We are on an organizer's custom domain
|
||||||
if 'organizer' in url.kwargs and url.kwargs['organizer']:
|
if 'organizer' in url.kwargs and url.kwargs['organizer']:
|
||||||
if url.kwargs['organizer'] != request.organizer.slug:
|
if url.kwargs['organizer'] != request.organizer.slug:
|
||||||
@@ -277,12 +280,20 @@ def _detect_event(request, require_live=True, require_plugin=None):
|
|||||||
organizer=request.organizer,
|
organizer=request.organizer,
|
||||||
)
|
)
|
||||||
|
|
||||||
# If this event has a custom domain, send the user there
|
# If this event has a custom domain or is not available on this alt domain, send the user there
|
||||||
domain = get_event_domain(request.event)
|
domain, domainmode = get_event_domain(request.event, fallback=False, return_mode=True)
|
||||||
if domain:
|
if not domain and request_domain_mode == KnownDomain.MODE_ORG_ALT_DOMAIN:
|
||||||
|
path = request.get_full_path().split("/", 2)[-1]
|
||||||
|
r = redirect_to_url(build_absolute_uri(request.event, "presale:event.index") + path)
|
||||||
|
r['Access-Control-Allow-Origin'] = '*'
|
||||||
|
return r
|
||||||
|
elif domain and domain != request.host:
|
||||||
if request.port and request.port not in (80, 443):
|
if request.port and request.port not in (80, 443):
|
||||||
domain = '%s:%d' % (domain, request.port)
|
domain = '%s:%d' % (domain, request.port)
|
||||||
path = request.get_full_path().split("/", 2)[-1]
|
if domainmode == KnownDomain.MODE_EVENT_DOMAIN:
|
||||||
|
path = request.get_full_path().split("/", 2)[-1]
|
||||||
|
else:
|
||||||
|
path = request.get_full_path()
|
||||||
r = redirect_to_url(urljoin('%s://%s' % (request.scheme, domain), path))
|
r = redirect_to_url(urljoin('%s://%s' % (request.scheme, domain), path))
|
||||||
r['Access-Control-Allow-Origin'] = '*'
|
r['Access-Control-Allow-Origin'] = '*'
|
||||||
return r
|
return r
|
||||||
@@ -299,11 +310,14 @@ def _detect_event(request, require_live=True, require_plugin=None):
|
|||||||
request.organizer = request.event.organizer
|
request.organizer = request.event.organizer
|
||||||
|
|
||||||
# If this event has a custom domain, send the user there
|
# If this event has a custom domain, send the user there
|
||||||
domain = get_event_domain(request.event)
|
domain, domainmode = get_event_domain(request.event, fallback=False, return_mode=True)
|
||||||
if domain:
|
if domain:
|
||||||
if request.port and request.port not in (80, 443):
|
if request.port and request.port not in (80, 443):
|
||||||
domain = '%s:%d' % (domain, request.port)
|
domain = '%s:%d' % (domain, request.port)
|
||||||
path = request.get_full_path().split("/", 3)[-1]
|
if domainmode == KnownDomain.MODE_EVENT_DOMAIN:
|
||||||
|
path = request.get_full_path().split("/", 3)[-1]
|
||||||
|
else:
|
||||||
|
path = request.get_full_path().split("/", 2)[-1]
|
||||||
r = redirect_to_url(urljoin('%s://%s' % (request.scheme, domain), path))
|
r = redirect_to_url(urljoin('%s://%s' % (request.scheme, domain), path))
|
||||||
r['Access-Control-Allow-Origin'] = '*'
|
r['Access-Control-Allow-Origin'] = '*'
|
||||||
return r
|
return r
|
||||||
@@ -377,6 +391,7 @@ def _detect_event(request, require_live=True, require_plugin=None):
|
|||||||
except Event.DoesNotExist:
|
except Event.DoesNotExist:
|
||||||
try:
|
try:
|
||||||
if hasattr(request, 'organizer_domain'):
|
if hasattr(request, 'organizer_domain'):
|
||||||
|
# Redirect for case-insensitive event slug
|
||||||
event = request.organizer.events.get(
|
event = request.organizer.events.get(
|
||||||
slug__iexact=url.kwargs['event'],
|
slug__iexact=url.kwargs['event'],
|
||||||
organizer=request.organizer,
|
organizer=request.organizer,
|
||||||
@@ -388,6 +403,7 @@ def _detect_event(request, require_live=True, require_plugin=None):
|
|||||||
return r
|
return r
|
||||||
else:
|
else:
|
||||||
if 'event' in url.kwargs and 'organizer' in url.kwargs:
|
if 'event' in url.kwargs and 'organizer' in url.kwargs:
|
||||||
|
# Redirect for case-insensitive event or organizer slug
|
||||||
event = Event.objects.select_related('organizer').get(
|
event = Event.objects.select_related('organizer').get(
|
||||||
slug__iexact=url.kwargs['event'],
|
slug__iexact=url.kwargs['event'],
|
||||||
organizer__slug__iexact=url.kwargs['organizer']
|
organizer__slug__iexact=url.kwargs['organizer']
|
||||||
@@ -403,6 +419,7 @@ def _detect_event(request, require_live=True, require_plugin=None):
|
|||||||
raise Http404(_('The selected event was not found.'))
|
raise Http404(_('The selected event was not found.'))
|
||||||
except Organizer.DoesNotExist:
|
except Organizer.DoesNotExist:
|
||||||
if 'organizer' in url.kwargs:
|
if 'organizer' in url.kwargs:
|
||||||
|
# Redirect for case-insensitive organizer slug
|
||||||
try:
|
try:
|
||||||
organizer = Organizer.objects.get(
|
organizer = Organizer.objects.get(
|
||||||
slug__iexact=url.kwargs['organizer']
|
slug__iexact=url.kwargs['organizer']
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class RedirectBackMixin:
|
|||||||
self.redirect_field_name,
|
self.redirect_field_name,
|
||||||
self.request.GET.get(self.redirect_field_name, '')
|
self.request.GET.get(self.redirect_field_name, '')
|
||||||
)
|
)
|
||||||
hosts = list(KnownDomain.objects.filter(event__organizer=self.request.organizer).values_list('domainname', flat=True))
|
hosts = list(KnownDomain.objects.filter(organizer=self.request.organizer).values_list('domainname', flat=True))
|
||||||
siteurlsplit = urlsplit(settings.SITE_URL)
|
siteurlsplit = urlsplit(settings.SITE_URL)
|
||||||
if siteurlsplit.port and siteurlsplit.port not in (80, 443):
|
if siteurlsplit.port and siteurlsplit.port not in (80, 443):
|
||||||
hosts = ['%s:%d' % (h, siteurlsplit.port) for h in hosts]
|
hosts = ['%s:%d' % (h, siteurlsplit.port) for h in hosts]
|
||||||
@@ -168,7 +168,7 @@ class LogoutView(View):
|
|||||||
return HttpResponseRedirect(next_page)
|
return HttpResponseRedirect(next_page)
|
||||||
|
|
||||||
def get_next_page(self):
|
def get_next_page(self):
|
||||||
if getattr(self.request, 'event_domain', False):
|
if getattr(self.request, 'domain_mode', 'system') in (KnownDomain.MODE_ORG_ALT_DOMAIN, KnownDomain.MODE_EVENT_DOMAIN):
|
||||||
# After we cleared the cookies on this domain, redirect to the parent domain to clear cookies as well
|
# After we cleared the cookies on this domain, redirect to the parent domain to clear cookies as well
|
||||||
next_page = eventreverse(self.request.organizer, 'presale:organizer.customer.logout', kwargs={})
|
next_page = eventreverse(self.request.organizer, 'presale:organizer.customer.logout', kwargs={})
|
||||||
if self.redirect_field_name in self.request.POST or self.redirect_field_name in self.request.GET:
|
if self.redirect_field_name in self.request.POST or self.redirect_field_name in self.request.GET:
|
||||||
@@ -188,7 +188,7 @@ class LogoutView(View):
|
|||||||
self.redirect_field_name,
|
self.redirect_field_name,
|
||||||
self.request.GET.get(self.redirect_field_name)
|
self.request.GET.get(self.redirect_field_name)
|
||||||
)
|
)
|
||||||
hosts = list(KnownDomain.objects.filter(event__organizer=self.request.organizer).values_list('domainname', flat=True))
|
hosts = list(KnownDomain.objects.filter(organizer=self.request.organizer).values_list('domainname', flat=True))
|
||||||
siteurlsplit = urlsplit(settings.SITE_URL)
|
siteurlsplit = urlsplit(settings.SITE_URL)
|
||||||
if siteurlsplit.port and siteurlsplit.port not in (80, 443):
|
if siteurlsplit.port and siteurlsplit.port not in (80, 443):
|
||||||
hosts = ['%s:%d' % (h, siteurlsplit.port) for h in hosts]
|
hosts = ['%s:%d' % (h, siteurlsplit.port) for h in hosts]
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ from pretix.helpers.formats.en.formats import (
|
|||||||
)
|
)
|
||||||
from pretix.helpers.http import redirect_to_url
|
from pretix.helpers.http import redirect_to_url
|
||||||
from pretix.helpers.thumb import get_thumbnail
|
from pretix.helpers.thumb import get_thumbnail
|
||||||
from pretix.multidomain.urlreverse import eventreverse
|
from pretix.multidomain.urlreverse import build_absolute_uri, eventreverse
|
||||||
from pretix.presale.forms.organizer import EventListFilterForm
|
from pretix.presale.forms.organizer import EventListFilterForm
|
||||||
from pretix.presale.ical import get_public_ical
|
from pretix.presale.ical import get_public_ical
|
||||||
from pretix.presale.views import OrganizerViewMixin
|
from pretix.presale.views import OrganizerViewMixin
|
||||||
@@ -1305,3 +1305,8 @@ class OrganizerFavicon(View):
|
|||||||
return redirect_to_url(get_thumbnail(icon_file, '32x32^', formats=settings.PILLOW_FORMATS_QUESTIONS_FAVICON).thumb.url)
|
return redirect_to_url(get_thumbnail(icon_file, '32x32^', formats=settings.PILLOW_FORMATS_QUESTIONS_FAVICON).thumb.url)
|
||||||
else:
|
else:
|
||||||
return redirect_to_url(static("pretixbase/img/favicon.ico"))
|
return redirect_to_url(static("pretixbase/img/favicon.ico"))
|
||||||
|
|
||||||
|
|
||||||
|
class RedirectToOrganizerIndex(View):
|
||||||
|
def get(self, *args, **kwargs):
|
||||||
|
return redirect_to_url(build_absolute_uri(self.request.organizer, "presale:organizer.index"))
|
||||||
|
|||||||
@@ -1967,7 +1967,7 @@ def test_pdf_data(token_client, organizer, event, order, django_assert_max_num_q
|
|||||||
assert not resp.data['positions'][0].get('pdf_data')
|
assert not resp.data['positions'][0].get('pdf_data')
|
||||||
|
|
||||||
# order list
|
# order list
|
||||||
with django_assert_max_num_queries(31):
|
with django_assert_max_num_queries(32):
|
||||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?pdf_data=true'.format(
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?pdf_data=true'.format(
|
||||||
organizer.slug, event.slug
|
organizer.slug, event.slug
|
||||||
))
|
))
|
||||||
@@ -1982,7 +1982,7 @@ def test_pdf_data(token_client, organizer, event, order, django_assert_max_num_q
|
|||||||
assert not resp.data['results'][0]['positions'][0].get('pdf_data')
|
assert not resp.data['results'][0]['positions'][0].get('pdf_data')
|
||||||
|
|
||||||
# position list
|
# position list
|
||||||
with django_assert_max_num_queries(34):
|
with django_assert_max_num_queries(35):
|
||||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/?pdf_data=true'.format(
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/?pdf_data=true'.format(
|
||||||
organizer.slug, event.slug
|
organizer.slug, event.slug
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -40,16 +40,21 @@ def env():
|
|||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_control_only_on_main_domain(env, client):
|
def test_control_only_on_main_domain(env, client):
|
||||||
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0], mode=KnownDomain.MODE_ORG_DOMAIN)
|
||||||
r = client.get('/control/login', HTTP_HOST='foobar')
|
r = client.get('/control/login', HTTP_HOST='foobar')
|
||||||
assert r.status_code == 302
|
assert r.status_code == 302
|
||||||
assert r['Location'] == 'http://example.com/control/login'
|
assert r['Location'] == 'http://example.com/control/login'
|
||||||
|
|
||||||
KnownDomain.objects.create(domainname='barfoo', organizer=env[0], event=env[1])
|
KnownDomain.objects.create(domainname='barfoo', organizer=env[0], event=env[1], mode=KnownDomain.MODE_EVENT_DOMAIN)
|
||||||
r = client.get('/control/login', HTTP_HOST='barfoo')
|
r = client.get('/control/login', HTTP_HOST='barfoo')
|
||||||
assert r.status_code == 302
|
assert r.status_code == 302
|
||||||
assert r['Location'] == 'http://example.com/control/login'
|
assert r['Location'] == 'http://example.com/control/login'
|
||||||
|
|
||||||
|
KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
r = client.get('/control/login', HTTP_HOST='altfoo')
|
||||||
|
assert r.status_code == 302
|
||||||
|
assert r['Location'] == 'http://example.com/control/login'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_append_slash(env, client):
|
def test_append_slash(env, client):
|
||||||
@@ -80,6 +85,15 @@ def test_event_on_custom_domain(env, client):
|
|||||||
assert b'<meta property="og:title" content="MRMCD2015" />' in r.content
|
assert b'<meta property="og:title" content="MRMCD2015" />' in r.content
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_on_org_alt_domain(env, client):
|
||||||
|
d = KnownDomain.objects.create(domainname='foobar', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
d.event_assignments.create(event=env[1])
|
||||||
|
r = client.get('/2015/', HTTP_HOST='foobar')
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert b'<meta property="og:title" content="MRMCD2015" />' in r.content
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_path_without_trailing_slash_on_org_domain(env, client):
|
def test_path_without_trailing_slash_on_org_domain(env, client):
|
||||||
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
@@ -95,6 +109,15 @@ def test_event_with_org_domain_on_main_domain(env, client):
|
|||||||
assert r['Location'] == 'http://foobar/2015/'
|
assert r['Location'] == 'http://foobar/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_with_org_alt_domain_on_main_domain(env, client):
|
||||||
|
d = KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
d.event_assignments.create(event=env[1])
|
||||||
|
r = client.get('/mrmcd/2015/', HTTP_HOST='example.com')
|
||||||
|
assert r.status_code == 302
|
||||||
|
assert r['Location'] == 'http://foobar/2015/'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_event_with_custom_domain_on_main_domain(env, client):
|
def test_event_with_custom_domain_on_main_domain(env, client):
|
||||||
KnownDomain.objects.create(domainname='foobar', organizer=env[0], event=env[1])
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0], event=env[1])
|
||||||
@@ -112,6 +135,40 @@ def test_event_with_custom_domain_on_org_domain(env, client):
|
|||||||
assert r['Location'] == 'http://barfoo'
|
assert r['Location'] == 'http://barfoo'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_with_custom_domain_on_org_alt_domain(env, client):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
KnownDomain.objects.create(domainname='barfoo', organizer=env[0], event=env[1])
|
||||||
|
r = client.get('/2015/', HTTP_HOST='altfoo')
|
||||||
|
assert r.status_code == 302
|
||||||
|
assert r['Location'] == 'http://barfoo'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_with_org_alt_domain_on_org_domain(env, client):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0], mode=KnownDomain.MODE_ORG_DOMAIN)
|
||||||
|
d = KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
d.event_assignments.create(event=env[1])
|
||||||
|
|
||||||
|
r = client.get('/2015/', HTTP_HOST='foobar')
|
||||||
|
assert r.status_code == 302
|
||||||
|
assert r['Location'] == 'http://altfoo/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_without_org_alt_domain_on_org_alt_domain(env, client):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
r = client.get('/', HTTP_HOST='foobar')
|
||||||
|
assert r.status_code == 302
|
||||||
|
assert r['Location'] == 'http://example.com/mrmcd/'
|
||||||
|
|
||||||
|
KnownDomain.objects.create(domainname='foobaz', organizer=env[0], mode=KnownDomain.MODE_ORG_DOMAIN)
|
||||||
|
r = client.get('/', HTTP_HOST='foobar')
|
||||||
|
assert r.status_code == 302
|
||||||
|
assert r['Location'] == 'http://foobaz/'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_organizer_with_org_domain_on_main_domain(env, client):
|
def test_organizer_with_org_domain_on_main_domain(env, client):
|
||||||
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
@@ -143,6 +200,10 @@ def test_unknown_event_on_org_domain(env, client):
|
|||||||
r = client.get('/1234/', HTTP_HOST='foobar')
|
r = client.get('/1234/', HTTP_HOST='foobar')
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
r = client.get('/1234/', HTTP_HOST='altfoo')
|
||||||
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_cookie_domain_on_org_domain(env, client):
|
def test_cookie_domain_on_org_domain(env, client):
|
||||||
@@ -153,6 +214,16 @@ def test_cookie_domain_on_org_domain(env, client):
|
|||||||
assert r.client.cookies['pretix_session']['domain'] == ''
|
assert r.client.cookies['pretix_session']['domain'] == ''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_cookie_domain_on_org_alt_domain(env, client):
|
||||||
|
d = KnownDomain.objects.create(domainname='foobar', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
d.event_assignments.create(event=env[1])
|
||||||
|
client.post('/2015/cart/add', HTTP_HOST='foobar')
|
||||||
|
r = client.get('/2015/', HTTP_HOST='foobar')
|
||||||
|
assert r.client.cookies['pretix_csrftoken']['domain'] == ''
|
||||||
|
assert r.client.cookies['pretix_session']['domain'] == ''
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_cookie_domain_on_event_domain(env, client):
|
def test_cookie_domain_on_event_domain(env, client):
|
||||||
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
|||||||
@@ -62,6 +62,36 @@ def test_event_custom_domain_front_page(env):
|
|||||||
assert rendered == 'http://foobar/2015/'
|
assert rendered == 'http://foobar/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_event_domain_front_page(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0], event=env[1], mode=KnownDomain.MODE_EVENT_DOMAIN)
|
||||||
|
rendered = TEMPLATE_FRONT_PAGE.render(Context({
|
||||||
|
'event': env[1]
|
||||||
|
})).strip()
|
||||||
|
assert rendered == 'http://foobar/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_org_alt_domain_front_page(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0], mode=KnownDomain.MODE_ORG_DOMAIN)
|
||||||
|
d = KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
d.event_assignments.create(event=env[1])
|
||||||
|
rendered = TEMPLATE_FRONT_PAGE.render(Context({
|
||||||
|
'event': env[1]
|
||||||
|
})).strip()
|
||||||
|
assert rendered == 'http://altfoo/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_custom_org_alt_domain_unassigned_front_page(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0], mode=KnownDomain.MODE_ORG_DOMAIN)
|
||||||
|
KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
rendered = TEMPLATE_FRONT_PAGE.render(Context({
|
||||||
|
'event': env[1]
|
||||||
|
})).strip()
|
||||||
|
assert rendered == 'http://foobar/2015/'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_event_main_domain_kwargs(env):
|
def test_event_main_domain_kwargs(env):
|
||||||
rendered = TEMPLATE_KWARGS.render(Context({
|
rendered = TEMPLATE_KWARGS.render(Context({
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ def env():
|
|||||||
organizer=o, name='MRMCD2015', slug='2015',
|
organizer=o, name='MRMCD2015', slug='2015',
|
||||||
date_from=now()
|
date_from=now()
|
||||||
)
|
)
|
||||||
event.get_cache().clear()
|
event.cache.clear()
|
||||||
return o, event
|
return o, event
|
||||||
|
|
||||||
|
|
||||||
@@ -60,6 +60,16 @@ def test_event_org_domain_kwargs(env):
|
|||||||
assert eventreverse(env[1], 'presale:event.checkout', {'step': 'payment'}) == 'http://foobar/2015/checkout/payment/'
|
assert eventreverse(env[1], 'presale:event.checkout', {'step': 'payment'}) == 'http://foobar/2015/checkout/payment/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_org_alt_domain_kwargs(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
d = KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
assert eventreverse(env[1], 'presale:event.checkout', {'step': 'payment'}) == 'http://foobar/2015/checkout/payment/'
|
||||||
|
d.event_assignments.create(event=env[1])
|
||||||
|
with scopes_disabled():
|
||||||
|
assert eventreverse(Event.objects.get(pk=env[1].pk), 'presale:event.checkout', {'step': 'payment'}) == 'http://altfoo/2015/checkout/payment/'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_event_main_domain_kwargs(env):
|
def test_event_main_domain_kwargs(env):
|
||||||
assert eventreverse(env[1], 'presale:event.checkout', {'step': 'payment'}) == '/mrmcd/2015/checkout/payment/'
|
assert eventreverse(env[1], 'presale:event.checkout', {'step': 'payment'}) == '/mrmcd/2015/checkout/payment/'
|
||||||
@@ -72,6 +82,15 @@ def test_event_org_domain_front_page(env):
|
|||||||
assert eventreverse(env[0], 'presale:organizer.index') == 'http://foobar/'
|
assert eventreverse(env[0], 'presale:organizer.index') == 'http://foobar/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_org_alt_domain_front_page(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
d = KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
d.event_assignments.create(event=env[1])
|
||||||
|
assert eventreverse(env[1], 'presale:event.index') == 'http://altfoo/2015/'
|
||||||
|
assert eventreverse(env[0], 'presale:organizer.index') == 'http://foobar/'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_event_custom_domain_front_page(env):
|
def test_event_custom_domain_front_page(env):
|
||||||
KnownDomain.objects.create(domainname='barfoo', organizer=env[0], event=env[1])
|
KnownDomain.objects.create(domainname='barfoo', organizer=env[0], event=env[1])
|
||||||
@@ -109,8 +128,8 @@ def test_event_org_domain_keep_scheme(env):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
def test_event_main_domain_cache(env):
|
def test_event_main_domain_cache(env):
|
||||||
env[0].get_cache().clear()
|
env[0].cache.clear()
|
||||||
with assert_num_queries(1):
|
with assert_num_queries(2):
|
||||||
eventreverse(env[1], 'presale:event.index')
|
eventreverse(env[1], 'presale:event.index')
|
||||||
with assert_num_queries(0):
|
with assert_num_queries(0):
|
||||||
eventreverse(env[1], 'presale:event.index')
|
eventreverse(env[1], 'presale:event.index')
|
||||||
@@ -125,8 +144,8 @@ def test_event_main_domain_cache(env):
|
|||||||
})
|
})
|
||||||
def test_event_org_domain_cache(env):
|
def test_event_org_domain_cache(env):
|
||||||
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
env[0].get_cache().clear()
|
env[0].cache.clear()
|
||||||
with assert_num_queries(1):
|
with assert_num_queries(2):
|
||||||
eventreverse(env[1], 'presale:event.index')
|
eventreverse(env[1], 'presale:event.index')
|
||||||
with assert_num_queries(0):
|
with assert_num_queries(0):
|
||||||
eventreverse(env[1], 'presale:event.index')
|
eventreverse(env[1], 'presale:event.index')
|
||||||
@@ -142,13 +161,36 @@ def test_event_org_domain_cache(env):
|
|||||||
def test_event_custom_domain_cache(env):
|
def test_event_custom_domain_cache(env):
|
||||||
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
KnownDomain.objects.create(domainname='barfoo', organizer=env[0], event=env[1])
|
KnownDomain.objects.create(domainname='barfoo', organizer=env[0], event=env[1])
|
||||||
env[0].get_cache().clear()
|
env[0].cache.clear()
|
||||||
with assert_num_queries(1):
|
with assert_num_queries(1):
|
||||||
eventreverse(env[1], 'presale:event.index')
|
eventreverse(env[1], 'presale:event.index')
|
||||||
with assert_num_queries(0):
|
with assert_num_queries(0):
|
||||||
eventreverse(env[1], 'presale:event.index')
|
eventreverse(env[1], 'presale:event.index')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
@override_settings(CACHES={
|
||||||
|
'default': {
|
||||||
|
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||||
|
'LOCATION': 'unique-snowflake',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
@scopes_disabled()
|
||||||
|
def test_event_org_alt_domain_cache_clear(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
kd_alt = KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
env[0].cache.clear()
|
||||||
|
with assert_num_queries(2):
|
||||||
|
eventreverse(env[1], 'presale:event.index')
|
||||||
|
kd_alt.event_assignments.create(event=env[1])
|
||||||
|
with assert_num_queries(2):
|
||||||
|
ev = Event.objects.get(pk=env[1].pk)
|
||||||
|
assert ev.pk == env[1].pk
|
||||||
|
assert ev.organizer == env[0]
|
||||||
|
with assert_num_queries(1):
|
||||||
|
eventreverse(ev, 'presale:event.index')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@override_settings(CACHES={
|
@override_settings(CACHES={
|
||||||
'default': {
|
'default': {
|
||||||
@@ -160,14 +202,14 @@ def test_event_custom_domain_cache(env):
|
|||||||
def test_event_org_domain_cache_clear(env):
|
def test_event_org_domain_cache_clear(env):
|
||||||
kd = KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
kd = KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
env[0].cache.clear()
|
env[0].cache.clear()
|
||||||
with assert_num_queries(1):
|
with assert_num_queries(2):
|
||||||
eventreverse(env[1], 'presale:event.index')
|
eventreverse(env[1], 'presale:event.index')
|
||||||
kd.delete()
|
kd.delete()
|
||||||
with assert_num_queries(2):
|
with assert_num_queries(2):
|
||||||
ev = Event.objects.get(pk=env[1].pk)
|
ev = Event.objects.get(pk=env[1].pk)
|
||||||
assert ev.pk == env[1].pk
|
assert ev.pk == env[1].pk
|
||||||
assert ev.organizer == env[0]
|
assert ev.organizer == env[0]
|
||||||
with assert_num_queries(1):
|
with assert_num_queries(2):
|
||||||
eventreverse(ev, 'presale:event.index')
|
eventreverse(ev, 'presale:event.index')
|
||||||
|
|
||||||
|
|
||||||
@@ -190,7 +232,7 @@ def test_event_custom_domain_cache_clear(env):
|
|||||||
ev = Event.objects.get(pk=env[1].pk)
|
ev = Event.objects.get(pk=env[1].pk)
|
||||||
assert ev.pk == env[1].pk
|
assert ev.pk == env[1].pk
|
||||||
assert ev.organizer == env[0]
|
assert ev.organizer == env[0]
|
||||||
with assert_num_queries(1):
|
with assert_num_queries(2):
|
||||||
eventreverse(ev, 'presale:event.index')
|
eventreverse(ev, 'presale:event.index')
|
||||||
|
|
||||||
|
|
||||||
@@ -210,3 +252,11 @@ def test_event_custom_domain_absolute(env):
|
|||||||
def test_event_org_domain_absolute(env):
|
def test_event_org_domain_absolute(env):
|
||||||
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
assert build_absolute_uri(env[1], 'presale:event.index') == 'http://foobar/2015/'
|
assert build_absolute_uri(env[1], 'presale:event.index') == 'http://foobar/2015/'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_event_org_alt_domain_absolute(env):
|
||||||
|
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||||
|
d = KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
d.event_assignments.create(event=env[1])
|
||||||
|
assert build_absolute_uri(env[1], 'presale:event.index') == 'http://altfoo/2015/'
|
||||||
|
|||||||
@@ -378,6 +378,13 @@ def test_org_sso_login_new_customer_popup(env, client, provider):
|
|||||||
_sso_login(client, provider, popup_origin="https://popuporigin")
|
_sso_login(client, provider, popup_origin="https://popuporigin")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_org_sso_login_new_customer_popup_org_alt_domain(env, client, provider):
|
||||||
|
d = KnownDomain.objects.create(organizer=env[0], domainname="popuporigin", mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
d.event_assignments.create(event=env[1])
|
||||||
|
_sso_login(client, provider, popup_origin="https://popuporigin")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_org_sso_login_new_customer_popup_invalid_origin(env, client, provider):
|
def test_org_sso_login_new_customer_popup_invalid_origin(env, client, provider):
|
||||||
KnownDomain.objects.create(organizer=env[0], event=env[1], domainname="popuporigin")
|
KnownDomain.objects.create(organizer=env[0], event=env[1], domainname="popuporigin")
|
||||||
@@ -696,16 +703,21 @@ def client2():
|
|||||||
return Client()
|
return Client()
|
||||||
|
|
||||||
|
|
||||||
def _cross_domain_login(env, client, client2):
|
def _cross_domain_login(env, client, client2, org_alt=False):
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
customer = env[0].customers.create(email='john@example.org', is_verified=True)
|
customer = env[0].customers.create(email='john@example.org', is_verified=True)
|
||||||
customer.set_password('foo')
|
customer.set_password('foo')
|
||||||
customer.save()
|
customer.save()
|
||||||
KnownDomain.objects.create(domainname='org.test', organizer=env[0])
|
KnownDomain.objects.create(domainname='org.test', organizer=env[0])
|
||||||
KnownDomain.objects.create(domainname='event.test', organizer=env[0], event=env[1])
|
if org_alt:
|
||||||
|
d = KnownDomain.objects.create(domainname='event.test', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
|
||||||
|
d.event_assignments.create(event=env[1])
|
||||||
|
else:
|
||||||
|
KnownDomain.objects.create(domainname='event.test', organizer=env[0], event=env[1])
|
||||||
|
|
||||||
# Log in on org domain
|
# Log in on org domain
|
||||||
r = client.post('/account/login?next=https://event.test/redeem&request_cross_domain_customer_auth=true', {
|
path = '/conf/' if org_alt else '/'
|
||||||
|
r = client.post(f'/account/login?next=https://event.test{path}redeem&request_cross_domain_customer_auth=true', {
|
||||||
'email': 'john@example.org',
|
'email': 'john@example.org',
|
||||||
'password': 'foo',
|
'password': 'foo',
|
||||||
}, HTTP_HOST='org.test')
|
}, HTTP_HOST='org.test')
|
||||||
@@ -713,12 +725,12 @@ def _cross_domain_login(env, client, client2):
|
|||||||
|
|
||||||
u = urlparse(r.headers['Location'])
|
u = urlparse(r.headers['Location'])
|
||||||
assert u.netloc == 'event.test'
|
assert u.netloc == 'event.test'
|
||||||
assert u.path == '/redeem'
|
assert u.path == path + 'redeem'
|
||||||
q = parse_qs(u.query)
|
q = parse_qs(u.query)
|
||||||
assert 'cross_domain_customer_auth' in q
|
assert 'cross_domain_customer_auth' in q
|
||||||
|
|
||||||
# Take session over to event domain
|
# Take session over to event domain
|
||||||
r = client2.get(f'/?{u.query}', HTTP_HOST='event.test')
|
r = client2.get(f'{path}?{u.query}', HTTP_HOST='event.test')
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
assert b'john@example.org' in r.content
|
assert b'john@example.org' in r.content
|
||||||
|
|
||||||
@@ -727,12 +739,27 @@ def _cross_domain_login(env, client, client2):
|
|||||||
def test_cross_domain_login(env, client, client2):
|
def test_cross_domain_login(env, client, client2):
|
||||||
_cross_domain_login(env, client, client2)
|
_cross_domain_login(env, client, client2)
|
||||||
|
|
||||||
# Logged in on org domain
|
# Logged in on evnet domain
|
||||||
r = client.get('/', HTTP_HOST='event.test')
|
r = client.get('/', HTTP_HOST='event.test')
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
assert b'john@example.org' in r.content
|
assert b'john@example.org' in r.content
|
||||||
|
|
||||||
# Logged in on event domain
|
# Logged in on org domain
|
||||||
|
r = client2.get('/', HTTP_HOST='org.test')
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert b'john@example.org' in r.content
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_cross_domain_login_org_alt(env, client, client2):
|
||||||
|
_cross_domain_login(env, client, client2, org_alt=True)
|
||||||
|
|
||||||
|
# Logged in on org alt domain
|
||||||
|
r = client.get('/conf/', HTTP_HOST='event.test')
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert b'john@example.org' in r.content
|
||||||
|
|
||||||
|
# Logged in on org domain
|
||||||
r = client2.get('/', HTTP_HOST='org.test')
|
r = client2.get('/', HTTP_HOST='org.test')
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
assert b'john@example.org' in r.content
|
assert b'john@example.org' in r.content
|
||||||
|
|||||||
Reference in New Issue
Block a user