Private
Public Access
1
0

Merge branch 'release/v20.2.2'

This commit is contained in:
2023-11-07 18:12:11 +01:00
12 changed files with 206 additions and 19 deletions

View File

@@ -8,7 +8,7 @@ from .models import (
WorkoutComment, C2WorldClassAgePerformance, PlannedSession,
GeoCourse, GeoPolygon, GeoPoint, VirtualRace, VirtualRaceResult,
PaidPlan, IndoorVirtualRaceResult, ShareKey,
CourseStandard, StandardCollection, InstantPlan,
CourseStandard, StandardCollection, InstantPlan, UserMessage
)
# Register your models here so you can use them in the Admin module
@@ -170,6 +170,9 @@ class CourseStandardAdmin(admin.ModelAdmin):
class InstantPlanAdmin(admin.ModelAdmin):
list_display = ('name','duration','price')
class UserMessageAdmin(admin.ModelAdmin):
list_display = ('receiver','datetime','subject')
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
admin.site.register(Workout, WorkoutAdmin)
@@ -192,3 +195,4 @@ admin.site.register(ShareKey, ShareKeyAdmin)
admin.site.register(CourseStandard, CourseStandardAdmin)
admin.site.register(StandardCollection, StandardCollectionAdmin)
admin.site.register(InstantPlan, InstantPlanAdmin)
admin.site.register(UserMessage, UserMessageAdmin)

View File

@@ -1,5 +1,5 @@
from django.contrib.staticfiles import finders
from bs4 import BeautifulSoup
import os
import time
import gc
@@ -112,17 +112,22 @@ def send_template_email(from_email, to_email, subject,
else:
emailbounced = False
try:
usr = User.objects.get(email=to_email)
umsg = UserMessage(
receiver = usr.rower,
datetime = timezone.now(),
text = text_content,
subject=subject,
)
umsg.save()
except User.DoesNotExist:
pass
for recipient in to_email:
try:
soup = BeautifulSoup(html_content)
s2 = soup.body
usr = User.objects.get(email=recipient)
umsg = UserMessage(
receiver = usr.rower,
datetime = timezone.now(),
text = '{text}'.format(text=s2),
subject=subject,
)
umsg.save()
except User.DoesNotExist:
pass
if not emailbounced:
res = msg.send()

View File

@@ -1247,6 +1247,14 @@ class UserMessage(models.Model):
isread = models.BooleanField(default=False)
text = models.CharField(max_length=1000)
subject = models.CharField(max_length=100,default='Message')
def __str__(self):
return '{r1} {r2} {d} {subject}'.format(
r1 = self.receiver.user.first_name,
r2 = self.receiver.user.last_name,
d = self.datetime,
subject = self.subject
)
# requestor is user

View File

@@ -0,0 +1,24 @@
{% extends "emailbase.html" %}
{% block body %}
<p>New Contact Form Message</p>
<p>
From: {{ firstname }} {{ lastname }}
</p>
<p>
Email: {{ email }}
</p>
<p>
Subject: {{ subject }}
</p>
<p>
{{ message }}
</p>
<p>
Best Regards, the Rowsandall Team
</p>
{% endblock %}

View File

@@ -2,6 +2,14 @@
{% load rowerfilters %}
<h1><a href="/rowers/me/edit/">Profile</a></h1>
<ul class="cd-accordion-menu animated">
<li id="manage-messgs">
<a href="/rowers/me/messages/">
<i class="fas fa-envelope fa-fw"></i>&nbsp;Messages
{% if rower|usermessages %}
( {{ rower|usermessages }} )
{% endif %}
</a>
</li>
<li id="manage-prefs-simple">
<a href="/rowers/me/prefs/">
<i class="fas fa-sliders-v-square fa-fw"></i>&nbsp;Threshold

View File

@@ -0,0 +1,59 @@
{% extends "newbase.html" %}
{% block title %}Messages{% endblock %}
{% block main %}
<h1>{{ rower.user.first_name }}'s New Messages</h1>
<ul class="main-content">
{% for usermessage in usermessages %}
{% if not usermessage.isread %}
<li class="rounder">
<h2>{{ usermessage.subject }}</h2>
<p><em>{{ usermessage.datetime }}</em></p>
<p>
{{ usermessage.text|safe }}
</p>
{% if request.user.rower == usermessage.receiver %}
<p>
<a href="/rowers/me/messages/{{ usermessage.id }}/delete/">
<i class="fas fa-trash-alt fa-fw"></i>
</a>
<a href="/rowers/me/messages/{{ usermessage.id }}/markread/">
<i class="fas fa-check fa-fw"></i>
</a>
</p>
</li>
{% endif %}
{% endif %}
{% endfor %}
</ul>
<h1>{{ rower.user.first_name }}'s Previous Messages</h1>
<ul class="main-content">
{% for usermessage in usermessages %}
{% if usermessage.isread %}
<li class="rounder">
<h2>{{ usermessage.subject }}</h2>
<p><em>{{ usermessage.datetime }}</em></p>
<p>
{{ usermessage.text|safe }}
</p>
{% if request.user.rower == usermessage.receiver %}
<p>
<a href="/rowers/me/messages/{{ usermessage.id }}/delete/">
<i class="fas fa-trash-alt fa-fw"></i>
</a>
</p>
</li>
{% endif %}
{% endif %}
{% endfor %}
</ul>
{% endblock %}
{% block sidebar %}
{% include 'menu_profile.html' %}
{% endblock %}

View File

@@ -15,7 +15,7 @@ from rowers.models import (
course_length, WorkoutComment,
TrainingMacroCycle, TrainingMesoCycle, TrainingMicroCycle,
Rower, Workout, SiteAnnouncement, TeamInvite, TeamRequest, CoachOffer, CoachRequest,
VirtualRaceFollower, VirtualRace, favanalysischoices,
VirtualRaceFollower, VirtualRace, favanalysischoices, UserMessage,
Team, TrainingPlan, TrainingTarget)
from rowers.plannedsessions import (
@@ -56,6 +56,15 @@ def workoutdate(id): # pragma: no cover
except Workout.DoesNotExist:
return 'unknown'
@register.filter
def usermessages(rower):
try:
msgs = UserMessage.objects.filter(receiver=rower, isread=False)
return msgs.count()
except UserMessage.DoesNotExist:
pass
return 0
@register.filter
def isfollower(user, id):

Binary file not shown.

View File

@@ -650,6 +650,10 @@ urlpatterns = [
re_path(r'^alerts/(?P<id>\d+)/report/$',
views.alert_report_view, name='alert_report_view'),
re_path(r'^me/deactivate/$', views.deactivate_user, name='deactivate_user'),
re_path(r'^me/messages/$', views.user_messages, name='user_messages'),
re_path(r'^me/messages/(?P<id>\d+)/delete/$', views.user_message_delete, name='user_message_delete'),
re_path(r'^me/messages/(?P<id>\d+)/markread/$', views.user_message_markread, name='user_message_markread'),
re_path(r'^me/messages/user/(?P<userid>\d+)/$', views.user_messages, name='user_messages'),
re_path(r'^me/delete/$', views.remove_user, name='remove_user'),
re_path(r'^survey/$', views.survey, name='survey'),
re_path(r'^me/gdpr-optin-confirm/?/$',

View File

@@ -158,7 +158,8 @@ from rowers.models import (
VideoAnalysis, ShareKey,
StandardCollection, CourseStandard,
VirtualRaceFollower, TombStone, InstantPlan,
PlannedSessionStep,InStrokeAnalysis, ForceCurveAnalysis, SyncRecord
PlannedSessionStep,InStrokeAnalysis, ForceCurveAnalysis, SyncRecord,
UserMessage,
)
from rowers.models import ( RowerPowerForm, RowerHRZonesForm, SimpleRowerPowerForm,
RowerForm, RowerCPForm, GraphImage, AdvancedWorkoutForm,
@@ -1289,11 +1290,24 @@ def sendmail(request):
subject = 'Rowsandall Contact Form:'+form.cleaned_data['subject']
message = form.cleaned_data['message']
fullemail = firstname + " " + lastname + " " + "<" + email + ">"
try:
send_mail(subject, message, fullemail, ['info@rowsandall.com'])
except:
d = {
'firstname': firstname,
'lastname': lastname,
'email': email,
'subject': subject,
'message': message,
}
res = send_template_email('Rowsandall <info@rowsandall.com>',
['Rowsandall <info@rowsandall.com>'],
subject,
'contactformemail.html',
d
)
if res:
messages.info(request,"Your contact form was submitted")
else:
messages.error(
request, "Something went wrong trying to send the email")
request, "Something went wrong trying to send the form")
return HttpResponseRedirect('/rowers/email/thankyou/')
else:
if not success:

View File

@@ -248,6 +248,50 @@ def start_plantrial_view(request):
return HttpResponseRedirect(url)
@login_required()
@permission_required('rower.is_coach', fn=get_user_by_userid, raise_exception=True)
def user_messages(request,userid=0):
r = getrequestrowercoachee(request, userid=userid, notpermanent=True)
usermessages = UserMessage.objects.filter(receiver=r).order_by('-datetime')
return render(request,'user_messages.html',
{'usermessages':usermessages,
'rower':r})
@login_required()
def user_message_delete(request,id=0):
try:
msg = UserMessage.objects.get(id=id)
except UserMessage.DoesNotExist:
pass
if msg.receiver == request.user.rower:
msg.delete()
messages.info(request,'Deleted message {id}'.format(id=id))
else:
messages.error('You are not allowed to delete this message')
url = reverse('user_messages')
return HttpResponseRedirect(url)
@login_required()
def user_message_markread(request,id=0):
try:
msg = UserMessage.objects.get(id=id)
except UserMessage.DoesNotExist:
pass
if msg.receiver == request.user.rower:
msg.isread = True
msg.save()
messages.info(request,'Marked message {id} read'.format(id=id))
else:
messages.error('You are not allowed to change this message')
url = reverse('user_messages')
return HttpResponseRedirect(url)
# Page where user can manage his favorite charts
@login_required()

View File

@@ -166,6 +166,14 @@
{% endif %}
</a>
</li>
{% if user.rower|usermessages %}
<li>
<a class="" href="{% url 'user_messages' %}" title="Messages" id="id-messages">
<i class="fas fa-envelope fa-fw"></i>
({{ user.rower|usermessages }})
</a>
</li>
{% endif %}
<li>
<a class="" href="{% url 'logout' %}?next=/login/" title="Sign Out" id="id-logout">
<i class="fas fa-sign-out-alt "></i>