Improve new event creation workflow, fixes #56. Allow adding events without a host team (falls back to 'Personal' team), fixes #92. Lays the groundwork for 'Private' teams for #46.
This commit is contained in:
parent
74be8e4bd6
commit
57050075c0
17 changed files with 635 additions and 17 deletions
|
@ -68,9 +68,10 @@ admin.site.register(Sponsor, SponsorAdmin)
|
|||
|
||||
class TeamAdmin(admin.ModelAdmin):
|
||||
raw_id_fields = ('country', 'spr', 'city', 'owner_profile', 'admin_profiles', 'contact_profiles', 'sponsors')
|
||||
list_display = ('__str__', 'active', 'member_count', 'event_count', 'owner_profile', 'created_date', 'is_premium', 'premium_expires')
|
||||
list_filter = ('active', 'is_premium', 'organization', ('country',admin.RelatedOnlyFieldListFilter))
|
||||
list_display = ('__str__', 'active', 'member_count', 'event_count', 'owner_profile', 'created_date', 'access', 'is_premium')
|
||||
list_filter = ('active', 'access', 'is_premium', 'organization', ('country',admin.RelatedOnlyFieldListFilter))
|
||||
ordering = ('-created_date',)
|
||||
|
||||
def member_count(self, team):
|
||||
return team.members.all().count()
|
||||
member_count.short_description = 'Members'
|
||||
|
|
|
@ -270,6 +270,41 @@ class NewTeamEventForm(forms.ModelForm):
|
|||
cleaned_data['end_time'] = pytz.utc.localize(timezone.make_naive(event_tz.localize(timezone.make_naive(cleaned_data['end_time']))))
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class NewEventForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = Event
|
||||
fields = ['name', 'start_time', 'end_time']
|
||||
widgets = {
|
||||
'start_time': DateTimeWidget,
|
||||
'end_time': DateTimeWidget
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kargs):
|
||||
super().__init__(*args, **kargs)
|
||||
event_tz = pytz.timezone(self.instance.tz)
|
||||
if self.instance.local_start_time: self.initial['start_time'] = self.instance.local_start_time
|
||||
if self.instance.local_end_time: self.initial['end_time'] = self.instance.local_end_time
|
||||
print("Initial: %s" % self.initial)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
event_tz = pytz.timezone(self.instance.tz)
|
||||
print("Clean: %s" % cleaned_data)
|
||||
cleaned_data['start_time'] = pytz.utc.localize(timezone.make_naive(event_tz.localize(timezone.make_naive(cleaned_data['start_time']))))
|
||||
cleaned_data['end_time'] = pytz.utc.localize(timezone.make_naive(event_tz.localize(timezone.make_naive(cleaned_data['end_time']))))
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class NewEventDetailsForm(forms.ModelForm):
|
||||
recurrences = recurrence.forms.RecurrenceField(label="Repeat", required=False)
|
||||
|
||||
class Meta:
|
||||
model = Event
|
||||
fields = ['summary', 'recurrences', 'web_url', 'announce_url']
|
||||
|
||||
|
||||
class DeleteEventForm(forms.Form):
|
||||
confirm = forms.BooleanField(label="Yes, delete event", required=True)
|
||||
|
||||
|
|
24
events/migrations/0041_add_private_personal_team_types.py
Normal file
24
events/migrations/0041_add_private_personal_team_types.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 2.0 on 2018-08-11 17:08
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0040_add_org_membership_requests'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='access',
|
||||
field=models.SmallIntegerField(choices=[(0, 'Public'), (1, 'Personal'), (2, 'Private')], default=0, verbose_name='Access'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='orgteamrequest',
|
||||
name='requested_by',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='requested_org_memberships', to='events.UserProfile'),
|
||||
),
|
||||
]
|
|
@ -57,6 +57,14 @@ class UserProfile(models.Model):
|
|||
except:
|
||||
return "Unknown Profile"
|
||||
|
||||
@property
|
||||
def personal_team(self):
|
||||
teams = Team.objects.filter(access=Team.PERSONAL, owner_profile=self)
|
||||
if teams.count() > 0:
|
||||
return teams[0]
|
||||
else:
|
||||
return Team.objects.create(name=str(self), access=Team.PERSONAL, owner_profile=self, city=self.city)
|
||||
|
||||
def avatar_url(self):
|
||||
try:
|
||||
if self.avatar is None or self.avatar.name is None:
|
||||
|
@ -86,19 +94,19 @@ class UserProfile(models.Model):
|
|||
|
||||
@property
|
||||
def is_a_team_admin(self):
|
||||
return Member.objects.filter(user=self, role=Member.ADMIN).count() > 0
|
||||
return Member.objects.filter(user=self, role=Member.ADMIN, team__access__in=(Team.PUBLIC, Team.PRIVATE)).count() > 0
|
||||
|
||||
@property
|
||||
def administering(self):
|
||||
return [member.team for member in Member.objects.filter(user=self, role=Member.ADMIN).order_by('team__name')]
|
||||
return [member.team for member in Member.objects.filter(user=self, role=Member.ADMIN, team__access__in=(Team.PUBLIC, Team.PRIVATE)).order_by('team__name')]
|
||||
|
||||
@property
|
||||
def is_a_team_moderator(self):
|
||||
return Member.objects.filter(user=self, role__in=(Member.ADMIN, Member.MODERATOR)).count() > 0
|
||||
return Member.objects.filter(user=self, role__in=(Member.ADMIN, Member.MODERATOR), team__access__in=(Team.PUBLIC, Team.PRIVATE)).count() > 0
|
||||
|
||||
@property
|
||||
def moderating(self):
|
||||
return [member.team for member in Member.objects.filter(user=self, role__in=(Member.ADMIN, Member.MODERATOR)).order_by('team__name')]
|
||||
return [member.team for member in Member.objects.filter(user=self, role__in=(Member.ADMIN, Member.MODERATOR), team__access__in=(Team.PUBLIC, Team.PRIVATE)).order_by('team__name')]
|
||||
|
||||
def can_create_event(self, team):
|
||||
try:
|
||||
|
@ -299,10 +307,24 @@ class SponsorSerializer(serializers.ModelSerializer):
|
|||
'web_url',
|
||||
)
|
||||
|
||||
|
||||
class PublicTeamsManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(access=Team.PUBLIC)
|
||||
|
||||
class Team(models.Model):
|
||||
PUBLIC=0
|
||||
PERSONAL=1
|
||||
PRIVATE=2
|
||||
TYPES = [
|
||||
(PUBLIC, _("Public")),
|
||||
(PERSONAL, _("Personal")),
|
||||
(PRIVATE, _("Private")),
|
||||
]
|
||||
name = models.CharField(_("Team Name"), max_length=256, null=False, blank=False)
|
||||
slug = models.CharField(max_length=256, null=False, blank=False, unique=True)
|
||||
organization = models.ForeignKey(Organization, related_name='teams', null=True, blank=True, on_delete=models.CASCADE)
|
||||
access = models.SmallIntegerField(verbose_name=_("Access"), choices=TYPES, default=PUBLIC)
|
||||
|
||||
cover_img = models.ImageField(verbose_name=_('Cover Image'), upload_to='team_covers', null=True, blank=True)
|
||||
tile_img = ImageSpecField(source='cover_img',
|
||||
|
@ -352,6 +374,9 @@ class Team(models.Model):
|
|||
premium_started = models.DateTimeField(blank=True, null=True)
|
||||
premium_expires = models.DateTimeField(blank=True, null=True)
|
||||
|
||||
objects = models.Manager()
|
||||
public_objects = PublicTeamsManager()
|
||||
|
||||
@property
|
||||
def card_img_url(self):
|
||||
if self.tile_img is not None and self.tile_img.name is not None:
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item active">
|
||||
<a class="btn btn-primary" href="{% url 'create-event-team-select' %}"><i class="fa fa fa-calendar-plus-o"></i> Host a Get Together</a>
|
||||
<a class="btn btn-primary" href="{% url 'new-event-start' %}"><i class="fa fa fa-calendar-plus-o"></i> Host a Get Together</a>
|
||||
</li>
|
||||
{% if request.user.is_authenticated %}
|
||||
<li class="nav-item dropdown">
|
||||
|
|
|
@ -115,7 +115,11 @@
|
|||
{% else %}
|
||||
<h2>{{ event.name }}</h2>
|
||||
{% endif %}
|
||||
{% if team.access == team.PERSONAL %}
|
||||
<p class="text-muted">Hosted by <a href="{% url "show-profile" team.owner_profile.id %}">{{ team.owner_profile }}</a></p>
|
||||
{% else %}
|
||||
<p class="text-muted">Hosted by <a href="{% url "show-team-by-slug" team.slug %}">{{ team.name }}</a></p>
|
||||
{% endif %}
|
||||
{% if event.status != event.CANCELED and not request.user.profile.do_not_track %}
|
||||
{% if settings.SOCIAL_AUTH_TWITTER_KEY %}
|
||||
<a href="https://twitter.com/intent/tweet?text=I'm+having+a+get+together!%0D{{event.name|urlencode}}&original_referer={{event.get_full_url|urlencode}}&url={{event.get_full_url|urlencode}}&hashtags=gettogether" data-size="large" class="btn btn-twitter btn-sm"><i class="fa fa-twitter"></i> Tweet</a>
|
||||
|
|
231
get_together/templates/get_together/new_event/add_place.html
Normal file
231
get_together/templates/get_together/new_event/add_place.html
Normal file
|
@ -0,0 +1,231 @@
|
|||
{% extends "get_together/base.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
|
||||
<h2>Choose your meeting place</h2>
|
||||
<form action="{% url "new-event-add-place" event.id %}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" id="id_id" name="id" value="" />
|
||||
{% include "events/place_form.html" %}
|
||||
<div class="fluid-layout" id="place-map"></div>
|
||||
<br />
|
||||
<button type="submit" class="btn btn-primary">Add Place</button>
|
||||
</form>
|
||||
<a class="btn btn-secondary" href="{% url 'new-event-add-details' event.id %}">Skip</a>
|
||||
</div>
|
||||
<div id="map" class="col-md-6"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key={{settings.GOOGLE_MAPS_API_KEY}}&libraries=places"></script>
|
||||
<script type="text/javascript">
|
||||
/*
|
||||
* jQuery Google Map Plugin 0.2.3
|
||||
* https://wiki.ubuntu.com/ubuntu-django-foundations/map
|
||||
* Requires jQuery 1.4.2
|
||||
*
|
||||
* Copyright 2011, Ronnie van den Crommenacker
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
$.fn.extend({
|
||||
selectLocation: function (options) {
|
||||
var defaults = {
|
||||
html_lng: null,
|
||||
html_lat: null,
|
||||
html_tz: null,
|
||||
html_country: null,
|
||||
html_continent: null,
|
||||
marker_icon: null,
|
||||
markers: [],
|
||||
html_addr: null,
|
||||
mapOptions: {
|
||||
zoom: 12,
|
||||
center: {lat: {{event.team.city.latitude}}, lng: {{event.team.city.longitude}}},
|
||||
mapTypeId: google.maps.MapTypeId.ROADMAP,
|
||||
mapTypeControl: false
|
||||
}
|
||||
};
|
||||
options = $.extend(defaults, options);
|
||||
|
||||
function showPositionHTML(ll, map, google_place_id) {
|
||||
var geocoder = new google.maps.Geocoder();
|
||||
geocoder.geocode({'latLng': ll}, function(results, status) {
|
||||
if (status == google.maps.GeocoderStatus.OK) {
|
||||
if (results[0]) {
|
||||
$('#id_address').val(results[0].formatted_address);
|
||||
var name, city, spr, country = "";
|
||||
$.each(results[0].address_components, function(){
|
||||
if(this.types[0]=="country") {
|
||||
country = this.long_name
|
||||
} else if(this.types[0]=="administrative_area_level_1"){
|
||||
spr = this.long_name
|
||||
} else if(this.types[0]=="locality"){
|
||||
city = this.long_name
|
||||
}
|
||||
});
|
||||
if (google_place_id != null) {
|
||||
$("#id_name").val("")
|
||||
$("#id_name").attr("placeholder", "Searching...")
|
||||
var places = new google.maps.places.PlacesService(map);
|
||||
places.getDetails({'placeId': google_place_id},
|
||||
function(result, status) {
|
||||
$("#id_name").val(result.name);
|
||||
$("#id_place_url").val(result.website);
|
||||
}
|
||||
);
|
||||
}
|
||||
$.getJSON("/api/find_city/?country="+country+"&spr="+spr+"&city="+city,
|
||||
function(json) {
|
||||
if (json.id) {
|
||||
var selectField = $("#city_select");
|
||||
selectField.empty();
|
||||
selectField.append('<option value="'+ json.id +'" selected>'+ json.display + '</option>');
|
||||
selectField.lookup("refresh");
|
||||
|
||||
$("#id_tz").val(json.tz);
|
||||
$("#id_tz").selectmenu("refresh");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (options.html_lng && options.html_lat) {
|
||||
if (ll.lat() != null && ll.lng() != null) {
|
||||
options.html_lat.val(ll.lat());
|
||||
options.html_lng.val(ll.lng());
|
||||
if (options.html_tz && options.html_country && options.html_continent) {
|
||||
$.getJSON("http://ws.geonames.org/timezoneJSON?lat=" + ll.lat() + "&lng=" + ll.lng(),
|
||||
function(json) {
|
||||
$(options.html_tz).filter(function() {
|
||||
return $(this).text() == json.timezoneId;
|
||||
}).prop('selected', true);
|
||||
|
||||
$(options.html_country).filter(function() {
|
||||
return $(this).text() == json.countryName;
|
||||
}).prop('selected', true);
|
||||
|
||||
$.getJSON("http://ws.geonames.org/countryInfoJSON?country=" + json.countryCode,
|
||||
function(json) {
|
||||
if (typeof json.geonames[0].continentName !== "undefined") {
|
||||
$(options.html_continent).filter(function() {
|
||||
return $(this).text() == json.geonames[0].continentName;
|
||||
}).prop('selected', true);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function setMarker(map, ll, google_place_id) {
|
||||
var marker = null;
|
||||
|
||||
if (options.markers.length) {
|
||||
marker = options.markers[0];
|
||||
marker.setPosition(ll);
|
||||
marker.setAnimation(google.maps.Animation.DROP);
|
||||
} else {
|
||||
marker = new google.maps.Marker({
|
||||
map: map,
|
||||
position: ll,
|
||||
draggable: true,
|
||||
animation: google.maps.Animation.DROP
|
||||
});
|
||||
if (options.marker_icon) {
|
||||
marker.icon = options.marker_icon;
|
||||
}
|
||||
options.markers.push(marker);
|
||||
google.maps.event.addListener(options.markers[0], 'mouseup', function () {
|
||||
showPositionHTML(marker.getPosition(), map, google_place_id);
|
||||
});
|
||||
}
|
||||
|
||||
map.setCenter(ll);
|
||||
showPositionHTML(marker.getPosition(), map, google_place_id);
|
||||
}
|
||||
|
||||
return $(this).each(function (i, html_element) {
|
||||
map = new google.maps.Map($(html_element)[0], options.mapOptions),
|
||||
ll = null;
|
||||
|
||||
google.maps.event.addListener(map, 'click', function (event) {
|
||||
if (event.hasOwnProperty('placeId')) {
|
||||
setMarker(map, event.latLng, event.placeId);
|
||||
} else {
|
||||
setMarker(map, event.latLng);
|
||||
}
|
||||
});
|
||||
|
||||
if (options.html_lat.val() && options.html_lng.val()) {
|
||||
ll = new google.maps.LatLng(options.html_lat.val(), options.html_lng.val());
|
||||
setMarker(map, ll);
|
||||
}
|
||||
|
||||
$.getJSON("/api/places/", function(data) {
|
||||
for (let place of data) {
|
||||
var position = new google.maps.LatLng(place['latitude'], place['longitude'])
|
||||
var marker = new google.maps.Marker({
|
||||
position: position,
|
||||
label: place['name'],
|
||||
map: map,
|
||||
});
|
||||
google.maps.event.addListener(marker, 'click',function(event) {
|
||||
$("#id_id").val(place['id']);
|
||||
$("#id_name").val(place['name']);
|
||||
showPositionHTML(this.position, map);
|
||||
});
|
||||
}
|
||||
return;
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
}(jQuery));
|
||||
$("#map").selectLocation({
|
||||
html_lat: $("#id_latitude"),
|
||||
html_lng: $("#id_longitude")
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="{% static 'js/jquery-ui-lookup.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
$("#city_select").lookup({
|
||||
search: function(searchText, callback) {
|
||||
if (searchText.length < 3) return callback(searchText, []);
|
||||
$.getJSON("/api/cities/?q="+searchText, function(data) {
|
||||
var m = this.url.match(/q=([^&]+)/);
|
||||
var q = "";
|
||||
if (m && m.length > 0) {
|
||||
q = this.url.match(/q=([^&]+)/)[1]
|
||||
}
|
||||
|
||||
return callback(q, data);
|
||||
});
|
||||
},
|
||||
select: function( event, ui ) {
|
||||
$("#id_tz").val(ui.data.tz);
|
||||
$("#id_tz").selectmenu("refresh");
|
||||
}
|
||||
})
|
||||
$("#id_tz").selectmenu();
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -0,0 +1,33 @@
|
|||
{% extends "get_together/base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Host a Get Together</h2>
|
||||
|
||||
<form action="{% url "new-event-start" %}" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="form-group">
|
||||
{% include "events/event_form.html" %}
|
||||
<br />
|
||||
<button type="submit" class="btn btn-primary">Schedule event</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
|
||||
$.datepicker.setDefaults({
|
||||
showOn: 'focus',
|
||||
dateFormat: 'yy-mm-dd',
|
||||
});
|
||||
|
||||
$("#id_start_time_0").datepicker({altField: "#id_end_time_0", altFormat: "yy-mm-dd"});
|
||||
|
||||
$("#id_end_time_0").datepicker();
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -0,0 +1,22 @@
|
|||
{% extends "get_together/base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block meta %}
|
||||
<script type="text/javascript" src="{% static 'recurrence/js/recurrence.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'recurrence/js/recurrence-widget.js' %}"></script>
|
||||
<link href="{% static 'recurrence/css/recurrence.css' %}" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Provide some more information about your event</h2>
|
||||
|
||||
<form action="{% url "new-event-add-details" event.id %}" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="form-group">
|
||||
{% include "events/event_form.html" %}
|
||||
<br />
|
||||
<button type="submit" class="btn btn-primary">Save details</button>
|
||||
<a class="btn btn-secondary" href="{% url 'new-event-add-team' event.id %}">Skip</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
64
get_together/templates/get_together/new_event/pick_team.html
Normal file
64
get_together/templates/get_together/new_event/pick_team.html
Normal file
|
@ -0,0 +1,64 @@
|
|||
{% extends "get_together/base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block styles %}
|
||||
<link href="{% static 'css/bootstrap-album.css' %}" rel="stylesheet"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
{% if teams %}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<center>
|
||||
<h3>Which team is hosting this event?</h3>
|
||||
</center>
|
||||
</div>
|
||||
</div>
|
||||
<form action="{% url 'new-event-add-team' event.id %}" method="POST">
|
||||
{% csrf_token %}
|
||||
<div class="row">
|
||||
{% for team in teams %}
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4 box-shadow">
|
||||
<div class="card-banner">
|
||||
{% if team.category %}
|
||||
<img class="card-img-top" src="{{team.category.img_url}}" alt="{{team.name}}">
|
||||
{% else %}
|
||||
<img class="card-img-top" src="{% static 'img/team_placeholder.png' %}" alt="{{team.name}}">
|
||||
{% endif %}
|
||||
<p class="card-title">{{team.name}}</p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text"><strong>{{team.city}}</strong></p>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<button class="btn btn-outline-primary" name="team_id" value="{{team.id}}" type="submit">Host</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="row">
|
||||
<div class="col-2"></div>
|
||||
<div class="col-8">
|
||||
<center>
|
||||
<h3>You don't have any teams that can host this event, would you like to start one now?</h3>
|
||||
</center>
|
||||
</div>
|
||||
<div class="col-2"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row pb-5">
|
||||
<div class="col-12">
|
||||
<center>
|
||||
<a class="btn btn-success" href="{% url 'create-team' %}?event={{event.id}}">Create a new Team</a>
|
||||
<a class="btn btn-secondary" href="{{event.get_absolute_url}}">Skip</a>
|
||||
</center>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
<form action="{% url "create-team" %}" method="post" enctype="multipart/form-data" class="form">
|
||||
{% csrf_token %}
|
||||
{% if team.organization %}<input type="hidden" name="organization" value="{{team.organization.id}}" />{% endif %}
|
||||
{% if event %}<input type="hidden" name="event" value="{{event}}" />{% endif %}
|
||||
<p>{% include "events/new_team_form.html" %}</p>
|
||||
<p><button type="submit" class="btn btn-primary">Continue</button></p>
|
||||
</form>
|
||||
|
|
|
@ -77,6 +77,12 @@ urlpatterns = [
|
|||
path('team/<int:team_id>/+define/', views.define_new_team, name='define-team'),
|
||||
path('team/+create-event/', views.create_event_team_select, name='create-event-team-select'),
|
||||
path('team/<int:team_id>/+create-event/', views.create_event, name='create-event'),
|
||||
|
||||
path('+new-event/', views.new_event_start, name='new-event-start'),
|
||||
path('events/<int:event_id>/+new-event-place/', views.new_event_add_place, name='new-event-add-place'),
|
||||
path('events/<int:event_id>/+new-event-details/', views.new_event_add_details, name='new-event-add-details'),
|
||||
path('events/<int:event_id>/+new-event-team/', views.new_event_add_team, name='new-event-add-team'),
|
||||
|
||||
path('events/<int:event_id>/+edit/', views.edit_event, name='edit-event'),
|
||||
path('events/<int:event_id>/+attend/', views.attend_event, name='attend-event'),
|
||||
path('events/<int:event_id>/+attended/', views.attended_event, name='attended-event'),
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.contrib import messages
|
|||
from django.contrib.auth import logout as logout_user
|
||||
from django.shortcuts import render, redirect
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from django.db.models import Q
|
||||
|
||||
from events.models.locale import City
|
||||
from events.models.events import Event, Place, Attendee
|
||||
|
@ -30,6 +31,7 @@ from .places import *
|
|||
from .user import *
|
||||
from .new_user import *
|
||||
from .new_team import *
|
||||
from .new_event import *
|
||||
from .speakers import *
|
||||
from .utils import *
|
||||
|
||||
|
@ -41,10 +43,6 @@ DEFAULT_NEAR_DISTANCE = 100 # kilometeres
|
|||
@setup_wanted
|
||||
def home(request, *args, **kwards):
|
||||
context = {}
|
||||
if request.user.is_authenticated:
|
||||
user_teams = Team.objects.filter(owner_profile=request.user.profile)
|
||||
if len(user_teams) > 0:
|
||||
context['user_teams'] = user_teams
|
||||
|
||||
near_distance = int(request.GET.get("distance", DEFAULT_NEAR_DISTANCE))
|
||||
context['distance'] = near_distance
|
||||
|
@ -105,7 +103,11 @@ def home(request, *args, **kwards):
|
|||
context['minlng'] = minlng
|
||||
context['maxlng'] = maxlng
|
||||
|
||||
near_events = Searchable.objects.filter(latitude__gte=minlat, latitude__lte=maxlat, longitude__gte=minlng, longitude__lte=maxlng, end_time__gte=datetime.datetime.now())
|
||||
near_events = Searchable.objects.filter(latitude__gte=minlat,
|
||||
latitude__lte=maxlat,
|
||||
longitude__gte=minlng,
|
||||
longitude__lte=maxlng,
|
||||
end_time__gte=datetime.datetime.now())
|
||||
context['near_events'] = sorted(near_events, key=lambda searchable: location.searchable_distance_from(ll, searchable))
|
||||
|
||||
# # If there aren't any teams in the user's geoip area, show them the closest ones
|
||||
|
@ -113,12 +115,17 @@ def home(request, *args, **kwards):
|
|||
context['closest_events'] = sorted(Searchable.objects.filter(end_time__gte=datetime.datetime.now()),
|
||||
key=lambda searchable: location.searchable_distance_from(ll, searchable))[:3]
|
||||
|
||||
near_teams = Team.objects.filter(city__latitude__gte=minlat, city__latitude__lte=maxlat, city__longitude__gte=minlng, city__longitude__lte=maxlng)
|
||||
near_teams = Team.public_objects.filter(city__latitude__gte=minlat,
|
||||
city__latitude__lte=maxlat,
|
||||
city__longitude__gte=minlng,
|
||||
city__longitude__lte=maxlng
|
||||
).filter(Q(access=Team.PUBLIC) | Q(access=Team.PRIVATE,
|
||||
owner_profile=request.user.profile))
|
||||
context['near_teams'] = sorted(near_teams, key=lambda team: location.team_distance_from(ll, team))
|
||||
|
||||
# # If there aren't any teams in the user's geoip area, show them the closest ones
|
||||
if context['geoip_lookup'] and len(near_teams) < 1:
|
||||
context['closest_teams'] = sorted(Team.objects.all(), key=lambda team: location.team_distance_from(ll, team))[:3]
|
||||
context['closest_teams'] = sorted(Team.public_objects.all(), key=lambda team: location.team_distance_from(ll, team))[:3]
|
||||
except Exception as err:
|
||||
print("Error looking up nearby teams and events", err)
|
||||
traceback.print_exc()
|
||||
|
|
151
get_together/views/new_event.py
Normal file
151
get_together/views/new_event.py
Normal file
|
@ -0,0 +1,151 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
|
||||
from events.models.profiles import Team, UserProfile
|
||||
from events.models.events import Event, EventSeries, Attendee
|
||||
from events.forms import NewEventForm, NewPlaceForm, NewEventDetailsForm
|
||||
from events import location
|
||||
|
||||
import simple_ga as ga
|
||||
|
||||
@login_required
|
||||
def new_event_start(request):
|
||||
team = request.user.profile.personal_team
|
||||
|
||||
new_event = Event(team=team, created_by=request.user.profile)
|
||||
|
||||
if request.method == 'GET':
|
||||
form = NewEventForm(instance=new_event)
|
||||
|
||||
context = {
|
||||
'event': new_event,
|
||||
'team': team,
|
||||
'event_form': form,
|
||||
}
|
||||
return render(request, 'get_together/new_event/create_event.html', context)
|
||||
elif request.method == 'POST':
|
||||
form = NewEventForm(request.POST, instance=new_event)
|
||||
if form.is_valid:
|
||||
new_event = form.save()
|
||||
Attendee.objects.create(event=new_event, user=request.user.profile, role=Attendee.HOST, status=Attendee.YES)
|
||||
|
||||
messages.add_message(request, messages.SUCCESS, message=_('Your event has been scheduled! Next, find a place for your event.'))
|
||||
ga.add_event(request, action='new_event', category='activity', label=new_event.get_full_url())
|
||||
|
||||
return redirect('new-event-add-place', new_event.id)
|
||||
else:
|
||||
context = {
|
||||
'event': new_event,
|
||||
'team': team,
|
||||
'event_form': form,
|
||||
}
|
||||
return render(request, 'get_together/new_event/create_event.html', context)
|
||||
else:
|
||||
return redirect('home')
|
||||
|
||||
@login_required
|
||||
def new_event_add_place(request, event_id):
|
||||
event = get_object_or_404(Event, id=event_id)
|
||||
if not request.user.profile.can_edit_event(event):
|
||||
messages.add_message(request, messages.WARNING, message=_('You can not make changes to this event.'))
|
||||
return redirect(event.get_absolute_url())
|
||||
|
||||
if request.method == 'GET':
|
||||
form = NewPlaceForm()
|
||||
|
||||
context = {
|
||||
'event': event,
|
||||
'place_form': form,
|
||||
}
|
||||
return render(request, 'get_together/new_event/add_place.html', context)
|
||||
elif request.method == 'POST':
|
||||
form = NewPlaceForm(request.POST)
|
||||
if form.is_valid:
|
||||
if request.POST.get('id', None):
|
||||
form.instance.id = request.POST.get('id')
|
||||
new_place = form.save()
|
||||
event.place = new_place
|
||||
event.save()
|
||||
if event.series is not None and event.series.place is None:
|
||||
event.series.place = new_place;
|
||||
event.series.save()
|
||||
return redirect('new-event-add-details', event.id)
|
||||
else:
|
||||
context = {
|
||||
'event': event,
|
||||
'place_form': form,
|
||||
}
|
||||
return render(request, 'get_together/new_event/add_place.html', context)
|
||||
else:
|
||||
return redirect('home')
|
||||
|
||||
|
||||
@login_required
|
||||
def new_event_add_details(request, event_id):
|
||||
event = get_object_or_404(Event, id=event_id)
|
||||
if not request.user.profile.can_edit_event(event):
|
||||
messages.add_message(request, messages.WARNING, message=_('You can not make changes to this event.'))
|
||||
return redirect(event.get_absolute_url())
|
||||
|
||||
if request.method == 'GET':
|
||||
form = NewEventDetailsForm(instance=event)
|
||||
|
||||
context = {
|
||||
'event': event,
|
||||
'team': event.team,
|
||||
'event_form': form,
|
||||
}
|
||||
return render(request, 'get_together/new_event/detail_event.html', context)
|
||||
elif request.method == 'POST':
|
||||
form = NewEventDetailsForm(request.POST, instance=event)
|
||||
if form.is_valid:
|
||||
new_event = form.save()
|
||||
|
||||
if form.cleaned_data.get('recurrences', None):
|
||||
new_series = EventSeries.from_event(new_event, recurrences=form.cleaned_data['recurrences'])
|
||||
new_series.save()
|
||||
new_event.series = new_series
|
||||
new_event.save()
|
||||
|
||||
return redirect('new-event-add-team', new_event.id)
|
||||
else:
|
||||
context = {
|
||||
'event': event,
|
||||
'team': event.team,
|
||||
'event_form': form,
|
||||
}
|
||||
return render(request, 'get_together/new_event/detail_event.html', context)
|
||||
else:
|
||||
return redirect('home')
|
||||
|
||||
|
||||
@login_required
|
||||
def new_event_add_team(request, event_id):
|
||||
teams = request.user.profile.moderating
|
||||
event = get_object_or_404(Event, id=event_id)
|
||||
if not request.user.profile.can_edit_event(event):
|
||||
messages.add_message(request, messages.WARNING, message=_('You can not make changes to this event.'))
|
||||
return redirect(event.get_absolute_url())
|
||||
|
||||
context = {
|
||||
'event': event,
|
||||
'teams': teams,
|
||||
}
|
||||
if request.method == 'GET':
|
||||
return render(request, 'get_together/new_event/pick_team.html', context)
|
||||
elif request.method == 'POST':
|
||||
if 'team_id' in request.POST:
|
||||
team = Team.objects.get(id=request.POST.get('team_id'))
|
||||
event.team = team
|
||||
event.save()
|
||||
messages.add_message(request, messages.SUCCESS, message=_('Your event is ready! Now you can start inviting people to join you'))
|
||||
return redirect(event.get_absolute_url())
|
||||
else:
|
||||
return render(request, 'get_together/new_event/pick_team.html', context)
|
||||
else:
|
||||
return redirect('home')
|
||||
|
||||
|
|
@ -36,6 +36,8 @@ def start_new_team(request):
|
|||
'team': new_team,
|
||||
'team_form': form,
|
||||
}
|
||||
if 'event' in request.GET and request.GET['event'] != '':
|
||||
context['event'] = request.GET['event']
|
||||
return render(request, 'get_together/new_team/start_new_team.html', context)
|
||||
elif request.method == 'POST':
|
||||
if 'organization' in request.POST and request.POST['organization'] != '':
|
||||
|
@ -46,6 +48,14 @@ def start_new_team(request):
|
|||
if form.is_valid():
|
||||
new_team = form.save()
|
||||
new_team.save()
|
||||
if 'event' in request.POST and request.POST['event'] != '':
|
||||
try:
|
||||
event = Event.objects.get(id=request.POST['event'])
|
||||
event.team = new_team
|
||||
event.save()
|
||||
except:
|
||||
pass
|
||||
|
||||
Member.objects.create(team=new_team, user=request.user.profile, role=Member.ADMIN)
|
||||
ga.add_event(request, action='new_team', category='growth', label=new_team.name)
|
||||
return redirect('define-team', team_id=new_team.pk)
|
||||
|
@ -54,9 +64,11 @@ def start_new_team(request):
|
|||
'team': new_team,
|
||||
'team_form': form,
|
||||
}
|
||||
if 'event' in request.POST and request.POST['event'] != '':
|
||||
context['event'] = request.POST['event']
|
||||
return render(request, 'get_together/new_team/start_new_team.html', context)
|
||||
else:
|
||||
return redirect('home')
|
||||
return redirect('home')
|
||||
|
||||
def define_new_team(request, team_id):
|
||||
team = get_object_or_404(Team, id=team_id)
|
||||
|
|
|
@ -36,7 +36,7 @@ def teams_list(request, *args, **kwargs):
|
|||
return render(request, 'get_together/teams/list_teams.html', context)
|
||||
|
||||
def teams_list_all(request, *args, **kwargs):
|
||||
teams = Team.objects.all()
|
||||
teams = Team.public_objects.all()
|
||||
geo_ip = location.get_geoip(request)
|
||||
context = {
|
||||
'active': 'all',
|
||||
|
@ -47,6 +47,8 @@ def teams_list_all(request, *args, **kwargs):
|
|||
|
||||
def show_team_by_slug(request, team_slug):
|
||||
team = get_object_or_404(Team, slug=team_slug)
|
||||
if team.access == Team.PERSONAL:
|
||||
return redirect('show-profile', team.owner_profile.id)
|
||||
return show_team(request, team)
|
||||
|
||||
def show_team_by_id(request, team_id):
|
||||
|
|
|
@ -23,7 +23,7 @@ def get_nearby_teams(request, near_distance=DEFAULT_NEAR_DISTANCE):
|
|||
minlng = g.latlng[1]-(near_distance/(KM_PER_DEGREE_LNG*math.cos(math.radians(g.latlng[0]))))
|
||||
maxlng = g.latlng[1]+(near_distance/(KM_PER_DEGREE_LNG*math.cos(math.radians(g.latlng[0]))))
|
||||
|
||||
near_teams = Team.objects.filter(city__latitude__gte=minlat, city__latitude__lte=maxlat, city__longitude__gte=minlng, city__longitude__lte=maxlng)
|
||||
near_teams = Team.public_objects.filter(city__latitude__gte=minlat, city__latitude__lte=maxlat, city__longitude__gte=minlng, city__longitude__lte=maxlng)
|
||||
return near_teams
|
||||
except Exception as e:
|
||||
print("Error looking for local teams: ", e)
|
||||
|
|
Loading…
Reference in a new issue