Compare commits

..

2 Commits

Author SHA1 Message Date
7dd1c9bf30 subscription system backend added 2018-10-12 10:35:10 -04:00
20f47f02a8 profile link in header bar 2018-10-12 08:07:48 -04:00
14 changed files with 96 additions and 68 deletions

View File

@ -5,7 +5,7 @@ By popular demand, I'm building a better anonkun. It doesn't do much right now t
Python 3.6+ Python 3.6+
PostgreSQL 10.4+ PostgreSQL 10.4+
Redis 4.0.10+ Redis 4.0.10+
Python packages: `django psycopg2 channels channels_redis jinja2 argon2-cffi bleach requests python-magic django-taggit` Python packages: `django psycopg2 channels channels_redis jinja2 argon2-cffi bleach requests python-magic django-taggit django-user-messages`
## Install ## Install
``` ```

View File

@ -23,8 +23,10 @@
<span><a onclick="toggle_header();" href="javascript:void(0);"></a></span> <span><a onclick="toggle_header();" href="javascript:void(0);"></a></span>
</div> </div>
<ul id="alerts"> <ul id="alerts">
{% for message in get_messages(request) %} {% for message in get_messages(request=request) %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li> {% if "subscription" not in message.tags %}
<li class="{{ message.tags }}">{{ message }}</li>
{% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
<div id="content">{% block content %}{% endblock %}</div> <div id="content">{% block content %}{% endblock %}</div>

View File

@ -86,7 +86,7 @@ def message(socket, data):
m = Message( m = Message(
quest=quest, quest=quest,
message=message) message=message)
if user.username: if user.is_authenticated:
m.user = user m.user = user
m.save() m.save()
@ -551,7 +551,7 @@ def vote(socket, data):
option=option, option=option,
ip_address=ip_address ip_address=ip_address
) )
if user.username: if user.is_authenticated:
pv.user = user pv.user = user
pv.save() pv.save()

View File

@ -18,32 +18,7 @@
<script>window.onload = load;</script> <script>window.onload = load;</script>
{% endblock %} {% endblock %}
{% block header %} {% block header %}
{% if request.user == quest.owner %} {% include "quest/quest_header.html" %}
<span><a href="{{ url('quest:edit_quest', args=[quest_id, page_num]) }}">Edit Quest</a></span>
{% endif %}
<span id="pageSelection">
<select onChange="window.location.href=this.value">
<optgroup label="Pages">
{% for page in pages %}
<option value="{{ url('quest:quest', args=[quest_id, page.page_num]) }}"{% if page.page_num == page_num %} selected="yes" {% if vars.update({'next_page': loop.nextitem}) %}{% endif %}{% endif %}>{{ page.title }}</option>
{% endfor %}
</optgroup>
{% if appendices %}
<optgroup label="Appendices">
{% for appendix in appendices %}
<option value="{{ url('quest:quest', args=[quest_id, appendix.page_num]) }}"{% if appendix.page_num == page_num %} selected="yes"{% endif %}>{{ appendix.title }}</option>
{% endfor %}
</optgroup>
{% endif %}
</select>
</span>
<span id="live" style="display:{% if quest.live %}initial{% else %}none{% endif %};">
LIVE
</span>
<span id="liveIn" style="display:{% if quest.live_time and not quest.live %}initial{% else %}none{% endif %};">
Live in: <span id="liveCountdown"></span> (<span id="liveTime">{% if quest.live_time %}{{ localtime(quest.live_time).strftime('%Y-%m-%d %H:%M') }}{% endif %}</span>)
</span>
<span id="toggleChat"><a onclick="toggle_chat()" href="javascript:void(0);">{% if request.session.get("hide_chat") == True %}←{% else %}→{% endif %}</a></span>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="questPane" style="width:{% if request.session.get("hide_chat") == True %}100%{% else %}70%{% endif %};"> <div id="questPane" style="width:{% if request.session.get("hide_chat") == True %}100%{% else %}70%{% endif %};">

View File

@ -0,0 +1,31 @@
{% if request.user == quest.owner %}
<span><a href="{{ url('quest:edit_quest', args=[quest_id, page_num]) }}">Edit Quest</a></span>
{% endif %}
<span id="pageSelection">
<select onChange="window.location.href=this.value">
<optgroup label="Pages">
{% for page in pages %}
<option value="{{ url('quest:quest', args=[quest_id, page.page_num]) }}"{% if page.page_num == page_num %} selected="yes" {% if vars.update({'next_page': loop.nextitem}) %}{% endif %}{% endif %}>{{ page.title }}</option>
{% endfor %}
</optgroup>
{% if appendices %}
<optgroup label="Appendices">
{% for appendix in appendices %}
<option value="{{ url('quest:quest', args=[quest_id, appendix.page_num]) }}"{% if appendix.page_num == page_num %} selected="yes"{% endif %}>{{ appendix.title }}</option>
{% endfor %}
</optgroup>
{% endif %}
</select>
</span>
<span id="live" style="display:{% if quest.live %}initial{% else %}none{% endif %};">
LIVE
</span>
<span id="liveIn" style="display:{% if quest.live_time and not quest.live %}initial{% else %}none{% endif %};">
Live in: <span id="liveCountdown"></span> (<span id="liveTime">{% if quest.live_time %}{{ localtime(quest.live_time).strftime('%Y-%m-%d %H:%M') }}{% endif %}</span>)
</span>
<span id="space"></span>
{% if request.user.is_authenticated %}
<span id="profileLink"><a href="{{ url('user:profile', args=[request.user.id]) }}">{{ request.user.username }}</a></span>
{% endif %}
<span id="toggleChat"><a onclick="toggle_chat()" href="javascript:void(0);">{% if request.session.get("hide_chat") == True %}←{% else %}→{% endif %}</a></span>

View File

@ -20,37 +20,7 @@
<script>window.onload = load;</script> <script>window.onload = load;</script>
{% endblock %} {% endblock %}
{% block header %} {% block header %}
{% if request.user == quest.owner %} {% include "quest/quest_header.html" %}
<span><a href="{{ url('quest:edit_quest', args=[quest_id, page_num]) }}">Edit Quest</a></span>
{% endif %}
<span>
<select onChange="window.location.href=this.value">
<optgroup label="Pages">
{% for page in pages %}
<option value="{{ url('quest:quest', args=[quest_id, page.page_num]) }}"{% if page.page_num == page_num %} selected="yes" {% if vars.update({'next_page': loop.nextitem }) %}{% endif %}{% endif %}>{{ page.title }}</option>
{% endfor %}
</optgroup>
{% if appendices %}
<optgroup label="Appendices">
{% for appendix in appendices %}
<option value="{{ url('quest:quest', args=[quest_id, appendix.page_num]) }}"{% if appendix.page_num == page_num %} selected="yes"{% endif %}>{{ appendix.title }}</option>
{% endfor %}
</optgroup>
{% endif %}
</select>
</span>
{% if quest.live %}
<span id="live">
LIVE
</span>
{% else %}
{% if quest.live_time %}
<span id="liveIn">
Live in: <span id="liveCountdown"></span> (<span id="liveTime">{{ localtime(quest.live_time).strftime('%Y-%m-%d %H:%M') }}</span>)
</span>
{% endif %}
{% endif %}
<span id="toggleChat"><a onclick="toggle_chat()" href="javascript:void(0);">{% if request.session.get("hide_chat") == True %}←{% else %}→{% endif %}</a></span>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="questPane" style="width:{% if request.session.get("hide_chat") == True %}100%{% else %}70%{% endif %};"> <div id="questPane" style="width:{% if request.session.get("hide_chat") == True %}100%{% else %}70%{% endif %};">
@ -67,6 +37,12 @@
<input type="submit"> <input type="submit">
</form> </form>
{% endif %} {% endif %}
{% if request.user.is_authenticated %}
<form id="subscribe" method="post" action="{{ url('quest:subscribe', kwargs={'quest_id': quest_id}) }}">
{{ csrf_input }}
<a onclick="document.getElementById('subscribe').submit()">Subscribe</a>
</form>
{% endif %}
<h3>Pages</h3> <h3>Pages</h3>
<ul> <ul>
{% for page in pages %} {% for page in pages %}

View File

@ -14,8 +14,8 @@ h3 {
padding: 0.25em; padding: 0.25em;
} }
#toggleChat { #space {
margin-left: auto; margin-right: auto;
} }
#questPane { #questPane {

View File

@ -10,6 +10,7 @@ app_name = 'quest'
urlpatterns = [ urlpatterns = [
path('', views.index, name='index'), path('', views.index, name='index'),
path('<int:quest_id>/new_tag', views.new_tag, name='new_tag'), path('<int:quest_id>/new_tag', views.new_tag, name='new_tag'),
path('<int:quest_id>/subscribe', views.subscribe, name='subscribe'),
path('<int:quest_id>/edit_quest', views.edit_quest, name='edit_quest'), path('<int:quest_id>/edit_quest', views.edit_quest, name='edit_quest'),
path('<int:quest_id>/<page_num>/edit_quest', views.edit_quest, name='edit_quest'), path('<int:quest_id>/<page_num>/edit_quest', views.edit_quest, name='edit_quest'),
path('<int:quest_id>', views.quest, name='quest'), path('<int:quest_id>', views.quest, name='quest'),

View File

@ -5,6 +5,7 @@ Quest and quest accessory views.
from datetime import timedelta, datetime, timezone from datetime import timedelta, datetime, timezone
import bleach import bleach
from user_messages import api
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from django.contrib import messages from django.contrib import messages
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
@ -85,6 +86,7 @@ def edit_quest(request, quest_id, page_num='0'):
Edit quest page. Only available to the QM. Edit quest page. Only available to the QM.
""" """
quest = Quest.objects.get(id=quest_id) quest = Quest.objects.get(id=quest_id)
prev_live = quest.live
if quest.owner != request.user: if quest.owner != request.user:
return redirect('quest:quest', quest_id=quest_id, page_num=page_num) return redirect('quest:quest', quest_id=quest_id, page_num=page_num)
if request.method == 'POST': if request.method == 'POST':
@ -119,6 +121,15 @@ def edit_quest(request, quest_id, page_num='0'):
if data['live_time']: if data['live_time']:
data['live_time'] =data['live_time'].strftime('%Y-%m-%d %H:%M') data['live_time'] =data['live_time'].strftime('%Y-%m-%d %H:%M')
send_to_websocket('live', quest_id, data) send_to_websocket('live', quest_id, data)
if prev_live == False and quest.live == True:
subscribers = quest.user_set.all()
for subscriber in subscribers:
api.info(
subscriber,
f"{quest.title} has gone live!",
extra_tags='subscription',
deliver_once=False
)
return redirect('quest:quest',quest_id=quest.id, page_num=page_num) return redirect('quest:quest',quest_id=quest.id, page_num=page_num)
else: else:
messages.error(request, "Error") messages.error(request, "Error")
@ -176,3 +187,13 @@ def new_tag(request, quest_id):
quest.tags.add(tag) quest.tags.add(tag)
return redirect('quest:quest', quest_id=quest_id, page_num='0') return redirect('quest:quest', quest_id=quest_id, page_num='0')
@require_POST
def subscribe(request, quest_id):
"""Endpoint for users to subscribe to a quest."""
if not request.user.is_authenticated:
return redirect('login:index')
request.user.subscriptions.add(Quest.objects.get(id=quest_id))
messages.success(request, "Subscribed")
return redirect('quest:quest', quest_id=quest_id, page_num='0')

View File

@ -3,8 +3,8 @@
Custom Jinja2 environment. Custom Jinja2 environment.
""" """
import jinja2 import jinja2
from user_messages import api
from django.urls import reverse from django.urls import reverse
from django.contrib import messages
from django.utils.timezone import template_localtime from django.utils.timezone import template_localtime
from django.contrib.staticfiles.storage import staticfiles_storage from django.contrib.staticfiles.storage import staticfiles_storage
@ -21,7 +21,7 @@ def environment(**options):
'url': reverse, 'url': reverse,
'static': staticfiles_storage.url, 'static': staticfiles_storage.url,
'get_messages': messages.get_messages, 'get_messages': api.get_messages,
'localtime': template_localtime, 'localtime': template_localtime,
}) })
return env return env

View File

@ -34,6 +34,7 @@ INSTALLED_APPS = [
'django.contrib.postgres', 'django.contrib.postgres',
'channels', 'channels',
'taggit', 'taggit',
'user_messages',
'user.apps.UserConfig', 'user.apps.UserConfig',
'homepage.apps.HomepageConfig', 'homepage.apps.HomepageConfig',
'quest.apps.QuestConfig', 'quest.apps.QuestConfig',
@ -73,7 +74,8 @@ TEMPLATES = [
'django.template.context_processors.debug', 'django.template.context_processors.debug',
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', #'django.contrib.messages.context_processors.messages',
'user_messages.context_processors.messages',
], ],
}, },
}, },

1
todo
View File

@ -4,7 +4,6 @@ Front page to show new quests
Webm posting Webm posting
(you) counter (you) counter
Account managament Account managament
Display profile link in header bar
Quote backlinks Quote backlinks
Email Email
RSS RSS

View File

@ -0,0 +1,19 @@
# Generated by Django 2.1.1 on 2018-10-12 13:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('quest', '0010_quest_banner_url'),
('user', '0002_user_anonymize'),
]
operations = [
migrations.AddField(
model_name='user',
name='subscriptions',
field=models.ManyToManyField(to='quest.Quest'),
),
]

View File

@ -9,6 +9,7 @@ from django.contrib.auth.models import AbstractUser
from django.core.validators import MinLengthValidator, MaxLengthValidator from django.core.validators import MinLengthValidator, MaxLengthValidator
from .validators import CharValidator from .validators import CharValidator
from quest.models import Quest
class User(AbstractUser): class User(AbstractUser):
""" """
@ -45,6 +46,7 @@ class User(AbstractUser):
help_text="Let's be honest, your name doesn't add anything to " \ help_text="Let's be honest, your name doesn't add anything to " \
+ "the conversation." + "the conversation."
) )
subscriptions = models.ManyToManyField(Quest)
def get_full_name(self): def get_full_name(self):
return None return None