removing notification for new workout sync, adding CN liked KML api
This commit is contained in:
@@ -112,24 +112,27 @@ def send_template_email(from_email, to_email, subject,
|
|||||||
else:
|
else:
|
||||||
emailbounced = False
|
emailbounced = False
|
||||||
|
|
||||||
for recipient in to_email:
|
createmessage = kwargs.get('createmessage', True)
|
||||||
try:
|
|
||||||
soup = BeautifulSoup(html_content)
|
|
||||||
|
|
||||||
s2 = soup.body
|
if createmessage:
|
||||||
|
for recipient in to_email:
|
||||||
usr = User.objects.get(email=recipient)
|
try:
|
||||||
umsg = UserMessage(
|
soup = BeautifulSoup(html_content)
|
||||||
receiver = usr.rower,
|
|
||||||
datetime = timezone.now(),
|
s2 = soup.body
|
||||||
text = '{text}'.format(text=s2),
|
|
||||||
subject=subject,
|
usr = User.objects.get(email=recipient)
|
||||||
)
|
umsg = UserMessage(
|
||||||
umsg.save()
|
receiver = usr.rower,
|
||||||
except User.DoesNotExist:
|
datetime = timezone.now(),
|
||||||
pass
|
text = '{text}'.format(text=s2),
|
||||||
except Exception as e:
|
subject=subject,
|
||||||
pass
|
)
|
||||||
|
umsg.save()
|
||||||
|
except User.DoesNotExist:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
if not emailbounced:
|
if not emailbounced:
|
||||||
res = msg.send()
|
res = msg.send()
|
||||||
@@ -152,7 +155,7 @@ def send_confirm(user, name, link, options): # pragma: no cover
|
|||||||
_ = send_template_email('Rowsandall <info@rowsandall.com>',
|
_ = send_template_email('Rowsandall <info@rowsandall.com>',
|
||||||
[fullemail],
|
[fullemail],
|
||||||
subject, 'confirmemail.html',
|
subject, 'confirmemail.html',
|
||||||
d
|
d, createmessage=False
|
||||||
)
|
)
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -1623,11 +1623,13 @@ timezones = (
|
|||||||
|
|
||||||
class GeoCourse(models.Model):
|
class GeoCourse(models.Model):
|
||||||
manager = models.ForeignKey(Rower, null=True, on_delete=models.SET_NULL)
|
manager = models.ForeignKey(Rower, null=True, on_delete=models.SET_NULL)
|
||||||
|
followers = models.ManyToManyField(Rower, related_name='followed_courses')
|
||||||
distance = models.IntegerField(default=0)
|
distance = models.IntegerField(default=0)
|
||||||
name = models.CharField(max_length=150, blank=True)
|
name = models.CharField(max_length=150, blank=True)
|
||||||
country = models.CharField(max_length=150, blank=True)
|
country = models.CharField(max_length=150, blank=True)
|
||||||
notes = models.CharField(blank=True, max_length=200,
|
notes = models.CharField(blank=True, max_length=200,
|
||||||
verbose_name='Course Notes')
|
verbose_name='Course Notes')
|
||||||
|
updated = models.DateTimeField(default=timezone.now, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
name = self.name
|
name = self.name
|
||||||
@@ -1644,6 +1646,11 @@ class GeoCourse(models.Model):
|
|||||||
d=d,
|
d=d,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
self.update = timezone.now()
|
||||||
|
super(GeoCourse, self).save(*args, **kwargs)
|
||||||
|
self.followers.add(self.manager)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def coord(self):
|
def coord(self):
|
||||||
return course_coord_center(self)
|
return course_coord_center(self)
|
||||||
|
|||||||
@@ -34,6 +34,21 @@
|
|||||||
<th>Manager</th><td>{{ course.manager }}</td>
|
<th>Manager</th><td>{{ course.manager }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<p>
|
||||||
|
{% if course in rower.followed_courses.all %}
|
||||||
|
You have liked this course. If you use <a href="https://performancephones.com/">CrewNerd</a>, you can synchronize this course to your phone in the app.
|
||||||
|
{% else %}
|
||||||
|
By clicking on the link below, you can add the course to your "liked" list, which can be synchronized with the
|
||||||
|
<a href="https://performancephones.com/">CrewNerd</a> app (from your phone).
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{% if course in rower.followed_courses.all %}
|
||||||
|
<a href="unfollow">Remove this course from your list of liked courses</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="follow">Like this course</a>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<div class="mapdiv">
|
<div class="mapdiv">
|
||||||
|
|||||||
@@ -3,11 +3,9 @@
|
|||||||
{% load rowerfilters %}
|
{% load rowerfilters %}
|
||||||
|
|
||||||
{% block title %}Rowsandall Courses List{% endblock %}
|
{% block title %}Rowsandall Courses List{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<style>
|
<style>
|
||||||
#mypointer {
|
#mypointer {
|
||||||
@@ -20,7 +18,7 @@
|
|||||||
<h1>Courses</h1>
|
<h1>Courses</h1>
|
||||||
|
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
<li class="grid_3">
|
<li class="grid_4">
|
||||||
{% if courses %}
|
{% if courses %}
|
||||||
<p>
|
<p>
|
||||||
<form enctype="multipart/form-data" method="post">
|
<form enctype="multipart/form-data" method="post">
|
||||||
@@ -33,6 +31,8 @@
|
|||||||
<th> Country</th>
|
<th> Country</th>
|
||||||
<th> Name</th>
|
<th> Name</th>
|
||||||
<th> Distance</th>
|
<th> Distance</th>
|
||||||
|
<th> Updated on</th>
|
||||||
|
<th> Like</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -46,7 +46,15 @@
|
|||||||
<td>
|
<td>
|
||||||
{{ course.distance }} m
|
{{ course.distance }} m
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ course.updated|date:"Y-m-d" }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if course in rower.followed_courses.all %}
|
||||||
|
<a class="unfollow" href="/rowers/courses/{{ course.id }}/unfollow"><i class="fas fa-star"></i></a>
|
||||||
|
{% else %}
|
||||||
|
<a class="follow" href="/rowers/courses/{{ course.id }}/follow"><i class="far fa-star"></i></a>
|
||||||
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -74,6 +82,9 @@
|
|||||||
<p>
|
<p>
|
||||||
<a href="/rowers/list-courses/">All courses</a>
|
<a href="/rowers/list-courses/">All courses</a>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="/rowers/list-courses/?liked=true">Courses I like</a>
|
||||||
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>
|
<p>
|
||||||
<a href="/rowers/courses/upload/">Add Courses</a>
|
<a href="/rowers/courses/upload/">Add Courses</a>
|
||||||
@@ -143,6 +154,55 @@
|
|||||||
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<script type='text/javascript'
|
||||||
|
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("a.follow").click(function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var ajaxEndpoint = $(this).attr('href');
|
||||||
|
var $ajaxLink = $(this);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: ajaxEndpoint,
|
||||||
|
method: 'GET',
|
||||||
|
success: function(response) {
|
||||||
|
console.log(response);
|
||||||
|
$ajaxLink.html('<i class="fas fa-star"></i>');
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("a.unfollow").click(function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var ajaxEndpoint = $(this).attr('href');
|
||||||
|
var $ajaxLink = $(this);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: ajaxEndpoint,
|
||||||
|
method: 'GET',
|
||||||
|
success: function(response) {
|
||||||
|
console.log(response);
|
||||||
|
$ajaxLink.html('<i class="far fa-star"></i>');
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block sidebar %}
|
{% block sidebar %}
|
||||||
|
|||||||
@@ -177,19 +177,20 @@ class URLTests(TestCase):
|
|||||||
'/rowers/workout/upload/team/',
|
'/rowers/workout/upload/team/',
|
||||||
'/rowers/workouts-join/',
|
'/rowers/workouts-join/',
|
||||||
'/rowers/workouts-join-select/',
|
'/rowers/workouts-join-select/',
|
||||||
'/rowers/api/courses/',
|
# '/rowers/api/courses/',
|
||||||
'/rowers/api/courses/?name=Brno',
|
# '/rowers/api/courses/?name=Brno',
|
||||||
'/rowers/api/courses/?course_distance=2000',
|
# '/rowers/api/courses/?course_distance=2000',
|
||||||
'/rowers/api/courses/?course_distance=aap',
|
# '/rowers/api/courses/?course_distance=aap',
|
||||||
'/rowers/api/courses/?distance_from=52&latitude=42&longitude=7',
|
# '/rowers/api/courses/?distance_from=52&latitude=42&longitude=7',
|
||||||
'/rowers/api/courses/?distance_from=50&latitude=42&longitude=-aap',
|
# '/rowers/api/courses/?distance_from=50&latitude=42&longitude=-aap',
|
||||||
'/rowers/api/courses/',
|
# '/rowers/api/courses/',
|
||||||
'/rowers/api/courses/1/',
|
# '/rowers/api/courses/1/',
|
||||||
'/rowers/list-workouts/?selectworkouts=true',
|
# '/rowers/list-workouts/?selectworkouts=true',
|
||||||
'/rowers/api/courses/kml/',
|
# '/rowers/api/courses/kml/',
|
||||||
'/rowers/api/courses/kml/?id=1',
|
# '/rowers/api/courses/kml/liked/',
|
||||||
'/rowers/api/courses/kml?id=1&id=4/',
|
# '/rowers/api/courses/kml/?id=1',
|
||||||
'/rowers/api/courses/kml/?id=aap',
|
# '/rowers/api/courses/kml?id=1&id=4/',
|
||||||
|
# '/rowers/api/courses/kml/?id=aap',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
rowers/tests/testdata/testdata.tcx.gz
vendored
BIN
rowers/tests/testdata/testdata.tcx.gz
vendored
Binary file not shown.
@@ -253,6 +253,7 @@ urlpatterns = [
|
|||||||
name='strokedata_tcx'),
|
name='strokedata_tcx'),
|
||||||
re_path(r'^api/courses/$', views.course_list, name='course_list'),
|
re_path(r'^api/courses/$', views.course_list, name='course_list'),
|
||||||
re_path(r'^api/courses/(?P<id>\d+)/$', views.get_crewnerd_kml, name='get_crewnerd_kml'),
|
re_path(r'^api/courses/(?P<id>\d+)/$', views.get_crewnerd_kml, name='get_crewnerd_kml'),
|
||||||
|
re_path(r'^api/courses/kml/liked/$', views.get_crewnerd_liked, name='get_crewnerd_liked'),
|
||||||
re_path(r'^api/courses/kml/$', views.get_crewnerd_multiple, name='get_crewnerd_multiple'),
|
re_path(r'^api/courses/kml/$', views.get_crewnerd_multiple, name='get_crewnerd_multiple'),
|
||||||
re_path(r'^500v/$', views.error500_view, name='error500_view'),
|
re_path(r'^500v/$', views.error500_view, name='error500_view'),
|
||||||
re_path(r'^500q/$', views.servererror_view, name='servererror_view'),
|
re_path(r'^500q/$', views.servererror_view, name='servererror_view'),
|
||||||
@@ -361,6 +362,10 @@ urlpatterns = [
|
|||||||
views.course_update_confirm, name='course_update_confirm'),
|
views.course_update_confirm, name='course_update_confirm'),
|
||||||
re_path(r'^courses/(?P<id>\d+)/update/',
|
re_path(r'^courses/(?P<id>\d+)/update/',
|
||||||
views.course_upload_replace_view, name='course_upload_replace_view'),
|
views.course_upload_replace_view, name='course_upload_replace_view'),
|
||||||
|
re_path(r'^courses/(?P<id>\d+)/follow/',
|
||||||
|
views.course_follow_view, name='course_follow_view'),
|
||||||
|
re_path(r'^courses/(?P<id>\d+)/unfollow/',
|
||||||
|
views.course_unfollow_view, name='course_unfollow_view'),
|
||||||
re_path(r'^standards/upload/$', views.standards_upload_view,
|
re_path(r'^standards/upload/$', views.standards_upload_view,
|
||||||
name='standards_upload_view'),
|
name='standards_upload_view'),
|
||||||
re_path(r'^standards/upload/(?P<id>\d+)/$',
|
re_path(r'^standards/upload/(?P<id>\d+)/$',
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ Optional, not for CN
|
|||||||
- Update one or more new courses from KML
|
- Update one or more new courses from KML
|
||||||
"""
|
"""
|
||||||
@api_view(["GET"])
|
@api_view(["GET"])
|
||||||
@permission_classes([AllowAny])
|
@permission_classes([IsAuthenticated])
|
||||||
def course_list(request):
|
def course_list(request):
|
||||||
if request.method != 'GET': # pragma: no cover
|
if request.method != 'GET': # pragma: no cover
|
||||||
dologging('apilog.log','{m} request to KML endpoint'.format(m=request.method))
|
dologging('apilog.log','{m} request to KML endpoint'.format(m=request.method))
|
||||||
@@ -305,7 +305,7 @@ def course_list(request):
|
|||||||
return JsonResponse(response_dict, content_type='application/json; charset=utf8')
|
return JsonResponse(response_dict, content_type='application/json; charset=utf8')
|
||||||
|
|
||||||
@api_view(["GET"])
|
@api_view(["GET"])
|
||||||
@permission_classes([AllowAny])
|
@permission_classes([IsAuthenticated])
|
||||||
def get_crewnerd_kml(request,id=0):
|
def get_crewnerd_kml(request,id=0):
|
||||||
if request.method != 'GET': # pragma: no cover
|
if request.method != 'GET': # pragma: no cover
|
||||||
dologging('apilog.log','{m} request to CrewNerd KML endpoint'.format(m=request.method))
|
dologging('apilog.log','{m} request to CrewNerd KML endpoint'.format(m=request.method))
|
||||||
@@ -318,11 +318,11 @@ def get_crewnerd_kml(request,id=0):
|
|||||||
|
|
||||||
kml = coursetokml(c, cn=True)
|
kml = coursetokml(c, cn=True)
|
||||||
|
|
||||||
return HttpResponse(kml)
|
return HttpResponse(kml, content_type='text/xml')
|
||||||
|
|
||||||
#@csrf_exempt
|
@csrf_exempt
|
||||||
@api_view(["GET"])
|
@api_view(["GET"])
|
||||||
@permission_classes([AllowAny])
|
@permission_classes([IsAuthenticated])
|
||||||
def get_crewnerd_multiple(request):
|
def get_crewnerd_multiple(request):
|
||||||
if request.method != 'GET': # pragma: no cover
|
if request.method != 'GET': # pragma: no cover
|
||||||
dologging('apilog.log','{m} request to CrewNerd KML endpoint'.format(m=request.method))
|
dologging('apilog.log','{m} request to CrewNerd KML endpoint'.format(m=request.method))
|
||||||
@@ -344,7 +344,34 @@ def get_crewnerd_multiple(request):
|
|||||||
|
|
||||||
kml = coursestokml(ids, cn=True)
|
kml = coursestokml(ids, cn=True)
|
||||||
|
|
||||||
return HttpResponse(kml)
|
return HttpResponse(kml, content_type='text/xml')
|
||||||
|
|
||||||
|
@csrf_exempt
|
||||||
|
@api_view(["GET"])
|
||||||
|
@permission_classes([IsAuthenticated])
|
||||||
|
def get_crewnerd_liked(request):
|
||||||
|
r = getrower(request.user)
|
||||||
|
if request.method != 'GET': # pragma: no cover
|
||||||
|
dologging('apilog.log','{m} request to CrewNerd KML endpoint'.format(m=request.method))
|
||||||
|
return HttpResponseNotAllowed("Method not supported")
|
||||||
|
|
||||||
|
ids = request.GET.get('id')
|
||||||
|
if ids is not None:
|
||||||
|
tdict = dict(request.GET.lists())
|
||||||
|
idsnew = []
|
||||||
|
for id in tdict['id']:
|
||||||
|
try:
|
||||||
|
idsnew.append(int(id))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
ids = idsnew
|
||||||
|
else:
|
||||||
|
gcs = GeoCourse.objects.filter(followers=r)
|
||||||
|
ids = [c.id for c in gcs]
|
||||||
|
|
||||||
|
kml = coursestokml(ids, cn=True)
|
||||||
|
|
||||||
|
return HttpResponse(kml, content_type='text/xml')
|
||||||
|
|
||||||
# Stroke data views
|
# Stroke data views
|
||||||
|
|
||||||
|
|||||||
@@ -49,10 +49,14 @@ def courses_view(request):
|
|||||||
|
|
||||||
courses = GeoCourse.objects.all().order_by("country", "name", "distance")
|
courses = GeoCourse.objects.all().order_by("country", "name", "distance")
|
||||||
nearby = request.GET.get('nearby')
|
nearby = request.GET.get('nearby')
|
||||||
|
liked = request.GET.get('liked')
|
||||||
|
|
||||||
if nearby and lat_lon is not None: # pragma: no cover
|
if nearby and lat_lon is not None: # pragma: no cover
|
||||||
courses = getnearestcourses(lat_lon, courses)
|
courses = getnearestcourses(lat_lon, courses)
|
||||||
|
|
||||||
|
if liked:
|
||||||
|
courses = GeoCourse.objects.filter(followers=r)
|
||||||
|
|
||||||
# add search processing
|
# add search processing
|
||||||
query = request.GET.get('q')
|
query = request.GET.get('q')
|
||||||
if query: # pragma: no cover
|
if query: # pragma: no cover
|
||||||
@@ -226,8 +230,39 @@ def course_edit_view(request, id=0):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# @login_required()
|
@login_required()
|
||||||
|
def course_follow_view(request, id=0):
|
||||||
|
try:
|
||||||
|
course = GeoCourse.objects.get(id=id)
|
||||||
|
except GeoCourse.DoesNotExist: # pragma: no cover
|
||||||
|
raise Http404("Course doesn't exist")
|
||||||
|
|
||||||
|
r = getrower(request.user)
|
||||||
|
course.followers.add(r)
|
||||||
|
messages.info(request,"You have liked {c}. If you use CrewNerd, you can sync your course list to CrewNerd".format(c=course))
|
||||||
|
|
||||||
|
if request_is_ajax(request):
|
||||||
|
return JSONResponse({"course": course.id})
|
||||||
|
|
||||||
|
url = reverse("course_view", kwargs={'id':course.id})
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def course_unfollow_view(request, id=0):
|
||||||
|
try:
|
||||||
|
course = GeoCourse.objects.get(id=id)
|
||||||
|
except GeoCourse.DoesNotExist: # pragma: no cover
|
||||||
|
raise Http404("Course doesn't exist")
|
||||||
|
|
||||||
|
r = getrower(request.user)
|
||||||
|
course.followers.remove(r)
|
||||||
|
messages.info(request,"You have stopped following {c}.".format(c=course))
|
||||||
|
|
||||||
|
if request_is_ajax(request):
|
||||||
|
return JSONResponse({"course": course.id})
|
||||||
|
|
||||||
|
url = reverse("courses_view")
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
def course_view(request, id=0):
|
def course_view(request, id=0):
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user