Add a webchat
This commit is contained in:
parent
b3154265c1
commit
5e7b176e39
23 changed files with 175 additions and 100 deletions
|
@ -73,6 +73,10 @@ You can set the following variables in the `.env` file:
|
|||
* `KHAGANAT_NSFW_TAGS`: Coma-separated list of words that triggers the content warning in logs, default is `\#nsfw`.
|
||||
* `KHAGANAT_NSFW_NAME`: Name of the cookie holding the NSFW allowance, default is `nsfw_allowed`.
|
||||
* `KHAGANAT_INTERNAL_IPS`: List of IP considered as internal, coma separated, default is `127.0.0.1,::1`.
|
||||
* `KHAGANAT_XMPP_BOSH_URL`: URL of the BOSH server used to contact the XMPP server. Default is empty.
|
||||
* `KHAGANAT_XMPP_JID`: The JID to use for the XMPP session. Default is empty.
|
||||
* `KHAGANAT_XMPP_ROOMS`: List of rooms to automatically join when connecting. Default is empty.
|
||||
* `KHAGANAT_XMPP_WEBSOCKET_URL`: URL of the websocket server used to contact the XMPP server. Default is empty.
|
||||
|
||||
|
||||
## Quick update
|
||||
|
|
7
chat/admin.py
Normal file
7
chat/admin.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from django.contrib import admin
|
||||
from .models import LogSource
|
||||
|
||||
class LogSourceAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'slug', 'hidden')
|
||||
|
||||
admin.site.register(LogSource, LogSourceAdmin)
|
|
@ -2,4 +2,4 @@ from django.apps import AppConfig
|
|||
|
||||
|
||||
class LogsConfig(AppConfig):
|
||||
name = 'logs'
|
||||
name = 'chat'
|
|
@ -2,7 +2,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: 1.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-02-04 19:45+0100\n"
|
||||
"POT-Creation-Date: 2019-07-23 15:09+0200\n"
|
||||
"PO-Revision-Date: 2018-01-27 18:35+0100\n"
|
||||
"Last-Translator: Khaganat <assoc@khaganat.net>\n"
|
||||
"Language-Team: Khaganat <assoc@khaganat.net>\n"
|
||||
|
@ -16,36 +16,36 @@ msgstr ""
|
|||
msgid "date"
|
||||
msgstr ""
|
||||
|
||||
#: templates/logs/entries.html:10 templates/logs/entries.html:21
|
||||
msgid "logs_back"
|
||||
msgstr "Back"
|
||||
#: templates/chat/chat_conversejs.html:15
|
||||
msgid "chat_title"
|
||||
msgstr "Khaganat's chat room"
|
||||
|
||||
#: templates/logs/index.html:4 templates/logs/index.html:8
|
||||
#: templates/chat/entries.html:4 templates/chat/entries.html:11
|
||||
msgid "logs_title"
|
||||
msgstr "Khaganat's logs"
|
||||
|
||||
#: templates/logs/index.html:32
|
||||
#: templates/chat/entries.html:21
|
||||
msgid "logs_no_logs_available"
|
||||
msgstr "No logs available."
|
||||
|
||||
#: templates/chat/entries.html:33
|
||||
msgid "go"
|
||||
msgstr ""
|
||||
|
||||
#: templates/logs/index.html:36
|
||||
#: templates/chat/entries.html:40
|
||||
#, python-format
|
||||
msgid "%(name)s is hidden."
|
||||
msgstr ""
|
||||
|
||||
#: templates/logs/index.html:37
|
||||
#: templates/chat/entries.html:41
|
||||
msgid "show"
|
||||
msgstr ""
|
||||
|
||||
#: templates/logs/index.html:39
|
||||
#: templates/chat/entries.html:43
|
||||
#, python-format
|
||||
msgid "%(name)s is published."
|
||||
msgstr ""
|
||||
|
||||
#: templates/logs/index.html:40
|
||||
#: templates/chat/entries.html:44
|
||||
msgid "hide"
|
||||
msgstr ""
|
||||
|
||||
#: templates/logs/index.html:51
|
||||
msgid "logs_no_logs_available"
|
||||
msgstr "No logs available."
|
|
@ -2,7 +2,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: 1.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-02-04 19:45+0100\n"
|
||||
"POT-Creation-Date: 2019-07-23 15:09+0200\n"
|
||||
"PO-Revision-Date: 2018-01-27 18:35+0100\n"
|
||||
"Last-Translator: Khaganat <assoc@khaganat.net>\n"
|
||||
"Language-Team: Khaganat <assoc@khaganat.net>\n"
|
||||
|
@ -16,36 +16,39 @@ msgstr ""
|
|||
msgid "date"
|
||||
msgstr ""
|
||||
|
||||
#: templates/logs/entries.html:10 templates/logs/entries.html:21
|
||||
msgid "logs_back"
|
||||
msgstr "Retour"
|
||||
#: templates/chat/chat_conversejs.html:15
|
||||
msgid "chat_title"
|
||||
msgstr "Salon de discussion de Khaganat"
|
||||
|
||||
#: templates/logs/index.html:4 templates/logs/index.html:8
|
||||
#: templates/chat/entries.html:4 templates/chat/entries.html:11
|
||||
msgid "logs_title"
|
||||
msgstr "Journaux de conversation de Khaganat"
|
||||
|
||||
#: templates/logs/index.html:32
|
||||
#: templates/chat/entries.html:21
|
||||
msgid "logs_no_logs_available"
|
||||
msgstr "Aucun journal de conversation disponible."
|
||||
|
||||
#: templates/chat/entries.html:33
|
||||
msgid "go"
|
||||
msgstr ""
|
||||
|
||||
#: templates/logs/index.html:36
|
||||
#: templates/chat/entries.html:40
|
||||
#, python-format
|
||||
msgid "%(name)s is hidden."
|
||||
msgstr "%(name)s est masqué."
|
||||
|
||||
#: templates/logs/index.html:37
|
||||
#: templates/chat/entries.html:41
|
||||
msgid "show"
|
||||
msgstr "montrer"
|
||||
|
||||
#: templates/logs/index.html:39
|
||||
#: templates/chat/entries.html:43
|
||||
#, python-format
|
||||
msgid "%(name)s is published."
|
||||
msgstr "%(name)s est publié."
|
||||
|
||||
#: templates/logs/index.html:40
|
||||
#: templates/chat/entries.html:44
|
||||
msgid "hide"
|
||||
msgstr "masquer"
|
||||
|
||||
#: templates/logs/index.html:51
|
||||
msgid "logs_no_logs_available"
|
||||
msgstr "Aucun journal de conversation disponible."
|
||||
#~ msgid "logs_back"
|
||||
#~ msgstr "Retour"
|
|
@ -1,5 +1,5 @@
|
|||
from django.core.management.base import BaseCommand, CommandError
|
||||
from logs.models import Entry
|
||||
from chat.models import Entry
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 2.0.1 on 2018-01-27 20:08
|
||||
# Generated by Django 2.2.3 on 2019-07-23 09:50
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
@ -13,17 +13,7 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Entry',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('hidden', models.BooleanField(default=False)),
|
||||
('created', models.DateTimeField()),
|
||||
('nick', models.CharField(max_length=128)),
|
||||
('content', models.CharField(max_length=2048)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Source',
|
||||
name='LogSource',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=128)),
|
||||
|
@ -31,9 +21,15 @@ class Migration(migrations.Migration):
|
|||
('hidden', models.BooleanField(default=False)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='entry',
|
||||
name='source',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='logs.Source'),
|
||||
migrations.CreateModel(
|
||||
name='LogEntry',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('hidden', models.BooleanField(default=False)),
|
||||
('created', models.DateTimeField()),
|
||||
('nick', models.CharField(max_length=128)),
|
||||
('content', models.CharField(max_length=2048)),
|
||||
('source', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='chat.LogSource')),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -1,7 +1,7 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class Source(models.Model):
|
||||
class LogSource(models.Model):
|
||||
name = models.CharField(max_length=128)
|
||||
slug = models.CharField(max_length=128, unique=True)
|
||||
hidden = models.BooleanField(default=False)
|
||||
|
@ -10,8 +10,8 @@ class Source(models.Model):
|
|||
return self.name
|
||||
|
||||
|
||||
class Entry(models.Model):
|
||||
source = models.ForeignKey(Source, on_delete=models.CASCADE)
|
||||
class LogEntry(models.Model):
|
||||
source = models.ForeignKey(LogSource, on_delete=models.CASCADE)
|
||||
hidden = models.BooleanField(default=False)
|
||||
created = models.DateTimeField()
|
||||
nick = models.CharField(max_length=128)
|
50
chat/templates/chat/chat_conversejs.html
Normal file
50
chat/templates/chat/chat_conversejs.html
Normal file
|
@ -0,0 +1,50 @@
|
|||
{% extends "khaganat/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block headers %}
|
||||
<!-- TODO: build it instead of using a CDN -->
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.conversejs.org/4.2.0/css/converse.min.css">
|
||||
<script src="https://cdn.conversejs.org/4.2.0/dist/converse.min.js" charset="utf-8"></script>
|
||||
<style>
|
||||
#converse-container {
|
||||
height: 800px; // TODO: change this!
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{% trans "chat_title" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="content-bloc">
|
||||
<div id="converse-container">
|
||||
<div id="conversejs"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block endscript %}
|
||||
<script>
|
||||
converse.initialize({
|
||||
allow_contact_removal: false,
|
||||
allow_contact_requests: false,
|
||||
allow_logout: false,
|
||||
allow_muc: true,
|
||||
allow_muc_invitations: false,
|
||||
allow_registration: false,
|
||||
anonymous: true,
|
||||
authentication: 'anonymous',
|
||||
auto_join_rooms: [
|
||||
{% for name in rooms %}'{{name}}',{% endfor %}
|
||||
],
|
||||
auto_login: true,
|
||||
{% if bosh_url %}bosh_service_url: '{{ bosh_url }}',{% endif %}
|
||||
debug: {{ debug|lower }},
|
||||
hide_open_bookmarks: false,
|
||||
{% if jid %}jid: '{{ jid }}',{% endif %}
|
||||
show_controlbox_by_default: true,
|
||||
sticky_controlbox: true,
|
||||
view_mode: 'embedded',
|
||||
{% if websocket_url %}websocket_url: '{{ websocket_url }}',{% endif %}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
24
chat/urls.py
Normal file
24
chat/urls.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.chat_view, name='chat'),
|
||||
path('logs/', views.LogEntriesView.as_view(), name='log_index'),
|
||||
path(
|
||||
'logs/<slug:source>/<int:year>/<int:month>/<int:day>/',
|
||||
views.LogEntriesView.as_view(),
|
||||
name='log_day'
|
||||
),
|
||||
path(
|
||||
'logs/switch/source/<int:pk>/',
|
||||
views.switch_log_source,
|
||||
name='log_switch_source'
|
||||
),
|
||||
path(
|
||||
'logs/switch/entry/<int:pk>/',
|
||||
views.switch_log_entry,
|
||||
name='log_switch_entry'
|
||||
),
|
||||
path('logs/search/', views.log_search_view, name='log_search'),
|
||||
]
|
|
@ -1,5 +1,5 @@
|
|||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.shortcuts import redirect, get_object_or_404
|
||||
from django.shortcuts import redirect, render, get_object_or_404
|
||||
from django.db.models.functions import TruncDate
|
||||
from django.db.models import Count
|
||||
from django.views import generic
|
||||
|
@ -7,12 +7,22 @@ from django.conf import settings
|
|||
from django.urls import reverse
|
||||
from django.http import Http404
|
||||
from nsfw import views as nsfw
|
||||
from .models import Source, Entry
|
||||
from .models import LogSource, LogEntry
|
||||
from .forms import SearchForm
|
||||
from utils import is_link_legit
|
||||
import datetime
|
||||
|
||||
|
||||
def chat_view(request):
|
||||
ctx = {
|
||||
'debug': settings.DEBUG,
|
||||
'bosh_url': settings.KHAGANAT_XMPP_BOSH_URL,
|
||||
'jid': settings.KHAGANAT_XMPP_JID,
|
||||
'rooms': settings.KHAGANAT_XMPP_ROOMS,
|
||||
'websocket_url': settings.KHAGANAT_XMPP_WEBSOCKET_URL,
|
||||
}
|
||||
return render(request, 'chat/chat_conversejs.html', ctx)
|
||||
|
||||
def _get_dates():
|
||||
now = datetime.date.today()
|
||||
start_date = now - datetime.timedelta(
|
||||
|
@ -36,16 +46,16 @@ def _switch_hidden(request, obj, pk):
|
|||
|
||||
|
||||
@staff_member_required
|
||||
def switch_source(request, pk):
|
||||
return _switch_hidden(request, Source, pk)
|
||||
def switch_log_source(request, pk):
|
||||
return _switch_hidden(request, LogSource, pk)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def switch_entry(request, pk):
|
||||
return _switch_hidden(request, Entry, pk)
|
||||
def switch_log_entry(request, pk):
|
||||
return _switch_hidden(request, LogEntry, pk)
|
||||
|
||||
|
||||
def search_view(request):
|
||||
def log_search_view(request):
|
||||
if request.method == 'POST':
|
||||
form = SearchForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
@ -59,8 +69,8 @@ def search_view(request):
|
|||
raise Http404('No search parameters.')
|
||||
|
||||
|
||||
class EntriesView(generic.ListView):
|
||||
template_name = 'logs/entries.html'
|
||||
class LogEntriesView(generic.ListView):
|
||||
template_name = 'chat/entries.html'
|
||||
context_object_name = 'entries'
|
||||
filter_nsfw = False
|
||||
|
||||
|
@ -104,7 +114,7 @@ class EntriesView(generic.ListView):
|
|||
|
||||
nb_max = settings.KHAGANAT_LOGS_MAX_DAYS
|
||||
nb_max -= settings.KHAGANAT_LOGS_MIN_DAYS
|
||||
lst = Entry.objects.filter(
|
||||
lst = LogEntry.objects.filter(
|
||||
source=source,
|
||||
)
|
||||
if not self.request.user.is_staff:
|
||||
|
@ -123,12 +133,12 @@ class EntriesView(generic.ListView):
|
|||
"""Return the current source."""
|
||||
if self.kwargs.get('source') is None:
|
||||
return None
|
||||
return Source.objects.get(slug=self.kwargs['source'])
|
||||
return LogSource.objects.get(slug=self.kwargs['source'])
|
||||
|
||||
def get_sources(self):
|
||||
"""Return available sources."""
|
||||
now, start_date, end_date = _get_dates()
|
||||
qs = Entry.objects.all()
|
||||
qs = LogEntry.objects.all()
|
||||
|
||||
if not self.request.user.is_staff:
|
||||
qs = qs.filter(
|
||||
|
@ -175,13 +185,13 @@ class EntriesView(generic.ListView):
|
|||
(now - dt).days < settings.KHAGANAT_LOGS_MIN_DAYS,
|
||||
))
|
||||
if out_of_bounds and not is_staff:
|
||||
return Entry.objects.none()
|
||||
return LogEntry.objects.none()
|
||||
src = self.get_source()
|
||||
if src is None:
|
||||
return Entry.objects.none()
|
||||
return LogEntry.objects.none()
|
||||
if src.hidden and not is_staff:
|
||||
return Entry.objects.none()
|
||||
qs = Entry.objects.filter(
|
||||
return LogEntry.objects.none()
|
||||
qs = LogEntry.objects.filter(
|
||||
source=src,
|
||||
created__year=dt.year
|
||||
).filter(
|
|
@ -41,15 +41,15 @@ INSTALLED_APPS = [
|
|||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'khaganat.apps.KhaganatConfig',
|
||||
'neluser.apps.NeluserConfig',
|
||||
'pages.apps.PagesConfig',
|
||||
'navbar.apps.NavbarConfig',
|
||||
'static_extra.apps.KhaganatStaticFilesConfig',
|
||||
'logs.apps.LogsConfig',
|
||||
'nsfw.apps.NsfwConfig',
|
||||
'npb.apps.NpbConfig',
|
||||
'bulma',
|
||||
'chat.apps.LogsConfig',
|
||||
'khaganat.apps.KhaganatConfig',
|
||||
'navbar.apps.NavbarConfig',
|
||||
'neluser.apps.NeluserConfig',
|
||||
'npb.apps.NpbConfig',
|
||||
'nsfw.apps.NsfwConfig',
|
||||
'pages.apps.PagesConfig',
|
||||
'static_extra.apps.KhaganatStaticFilesConfig',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
@ -196,3 +196,10 @@ if config('KHAGANAT_FORCE_HTTPS', default=False, cast=bool):
|
|||
KHAGANAT_NSFW_TAGS = config('KHAGANAT_NSFW_TAGS', default='\\#nsfw', cast=Csv())
|
||||
KHAGANAT_NSFW_NAME = config('KHAGANAT_NSFW_NAME', default='nsfw_allowed')
|
||||
KHAGANAT_NSFW_OK = ('y', 'yes', 't', 'true', '1')
|
||||
|
||||
# Converse.js
|
||||
|
||||
KHAGANAT_XMPP_BOSH_URL = config('KHAGANAT_XMPP_BOSH_URL', default='') or None
|
||||
KHAGANAT_XMPP_JID = config('KHAGANAT_XMPP_JID', default='') or None
|
||||
KHAGANAT_XMPP_ROOMS = config('KHAGANAT_XMPP_ROOMS', default='', cast=Csv()) or []
|
||||
KHAGANAT_XMPP_WEBSOCKET_URL = config('KHAGANAT_XMPP_WEBSOCKET_URL', default='') or None
|
||||
|
|
|
@ -58,5 +58,6 @@
|
|||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
{% block endscript %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -29,6 +29,6 @@ urlpatterns += i18n_patterns(
|
|||
path('account/', include('neluser.urls')),
|
||||
path('page/', include('pages.urls')),
|
||||
path('paste/', include('npb.urls', namespace='npb')),
|
||||
path('logs/', include('logs.urls')),
|
||||
path('chat/', include('chat.urls')),
|
||||
path('nsfw/', include('nsfw.urls')),
|
||||
)
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
from django.contrib import admin
|
||||
from .models import Source
|
||||
|
||||
admin.site.register(Source)
|
23
logs/urls.py
23
logs/urls.py
|
@ -1,23 +0,0 @@
|
|||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.EntriesView.as_view(), name='log_index'),
|
||||
path(
|
||||
'<slug:source>/<int:year>/<int:month>/<int:day>/',
|
||||
views.EntriesView.as_view(),
|
||||
name='log_day'
|
||||
),
|
||||
path(
|
||||
'switch/source/<int:pk>/',
|
||||
views.switch_source,
|
||||
name='log_switch_source'
|
||||
),
|
||||
path(
|
||||
'switch/entry/<int:pk>/',
|
||||
views.switch_entry,
|
||||
name='log_switch_entry'
|
||||
),
|
||||
path('search/', views.search_view, name='log_search'),
|
||||
]
|
Loading…
Reference in a new issue