port to new django, AI automated
This commit is contained in:
@@ -1,4 +1,31 @@
|
||||
from django.contrib import admin
|
||||
from simpleforum.models import Message
|
||||
|
||||
admin.site.register(Message)
|
||||
from .models import Message
|
||||
|
||||
|
||||
@admin.register(Message)
|
||||
class MessageAdmin(admin.ModelAdmin):
|
||||
"""Admin configuration for Message model."""
|
||||
|
||||
list_display = ("titel", "author", "creation_time")
|
||||
list_filter = ("creation_time", "author")
|
||||
search_fields = ("titel", "text", "author__username")
|
||||
date_hierarchy = "creation_time"
|
||||
ordering = ("-creation_time",)
|
||||
readonly_fields = ("creation_time",)
|
||||
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": ("titel", "text", "author"),
|
||||
},
|
||||
),
|
||||
(
|
||||
"Metadata",
|
||||
{
|
||||
"fields": ("creation_time",),
|
||||
"classes": ("collapse",),
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
30
simpleforum/migrations/0001_initial.py
Normal file
30
simpleforum/migrations/0001_initial.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# Generated by Django 5.1.15 on 2026-03-30 19:15
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Message',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('titel', models.CharField(max_length=100, verbose_name='titel')),
|
||||
('text', models.TextField(verbose_name='text')),
|
||||
('creation_time', models.DateTimeField(verbose_name='creation_time')),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Author')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-creation_time'],
|
||||
},
|
||||
),
|
||||
]
|
||||
0
simpleforum/migrations/__init__.py
Normal file
0
simpleforum/migrations/__init__.py
Normal file
@@ -1,12 +1,12 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from musicians.models import Musician
|
||||
from django.template.loader import get_template
|
||||
from django.template import Context
|
||||
|
||||
|
||||
class Message(models.Model):
|
||||
@@ -14,30 +14,41 @@ class Message(models.Model):
|
||||
text = models.TextField(blank=False, verbose_name=_("text"))
|
||||
|
||||
creation_time = models.DateTimeField(verbose_name=_("creation_time"))
|
||||
author = models.ForeignKey(User, verbose_name=_("Author"), on_delete=models.PROTECT)
|
||||
|
||||
def __unicode__(self):
|
||||
author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_("Author"))
|
||||
|
||||
class Meta:
|
||||
ordering = ["-creation_time"]
|
||||
|
||||
def __str__(self):
|
||||
return self.author.username + " : " + self.titel
|
||||
|
||||
|
||||
@receiver(post_save, sender=Message)
|
||||
def my_handler(sender, instance, created, **kwargs):
|
||||
def send_forum_notification(sender, instance, created, **kwargs):
|
||||
"""Send email notification when a new message is created."""
|
||||
if not created:
|
||||
return
|
||||
|
||||
receivers = [m.user.email for m in Musician.objects.all()]
|
||||
receivers = [m.user.email for m in Musician.objects.all() if m.user.email]
|
||||
|
||||
if not receivers:
|
||||
return
|
||||
|
||||
subject = "Blechreiz Forum: " + instance.titel
|
||||
from_email = 'forum@blechreiz.com'
|
||||
from_email = "forum@blechreiz.com"
|
||||
|
||||
c = {'messages': Message.objects.all().order_by('-creation_time')[:10]}
|
||||
context = {"messages": Message.objects.all().order_by("-creation_time")[:10]}
|
||||
|
||||
text_template = get_template("simpleforum/mail.txt")
|
||||
# html_template = get_template( "simpleforum/mail.html" )
|
||||
|
||||
text_content = text_template.render(Context(c))
|
||||
# html_content = html_template.render( Context(c) )
|
||||
text_content = render_to_string("simpleforum/mail.txt", context)
|
||||
|
||||
msg = EmailMultiAlternatives(subject, text_content, from_email, receivers)
|
||||
# msg.attach_alternative( html_content, "text/html" )
|
||||
msg.send()
|
||||
# Uncomment to add HTML version:
|
||||
# html_content = render_to_string("simpleforum/mail.html", context)
|
||||
# msg.attach_alternative(html_content, "text/html")
|
||||
|
||||
try:
|
||||
msg.send()
|
||||
except Exception:
|
||||
# Log the error but don't crash
|
||||
pass
|
||||
|
||||
@@ -1,152 +1,160 @@
|
||||
{% extends "website/base.html" %}
|
||||
|
||||
{% load sekizai_tags staticfiles youtubefilter %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
{% addtoblock "css" strip %}<link rel="stylesheet" href="{{STATIC_URL}}css/datepicker.css" type="text/css" media="screen" /> {% endaddtoblock %}
|
||||
{% addtoblock "css" strip %} <link rel="stylesheet" href="{{STATIC_URL}}css/blogpost.css" type="text/css" media="screen" /> {% endaddtoblock %}
|
||||
|
||||
|
||||
{% addtoblock "css" %}
|
||||
{% extends "website/base.html" %} {% load sekizai_tags static youtubefilter %}
|
||||
{% block content %} {% addtoblock "css" strip %}<link
|
||||
rel="stylesheet"
|
||||
href="{{STATIC_URL}}/css/datepicker.css"
|
||||
type="text/css"
|
||||
media="screen"
|
||||
/>
|
||||
{% endaddtoblock %} {% addtoblock "css" strip %}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{STATIC_URL}}/css/blogpost.css"
|
||||
type="text/css"
|
||||
media="screen"
|
||||
/>
|
||||
{% endaddtoblock %} {% addtoblock "css" %}
|
||||
<style>
|
||||
.embed-container {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%; /* 16/9 ratio */
|
||||
padding-top: 30px; /* IE6 workaround*/
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.embed-container iframe,
|
||||
.embed-container object,
|
||||
.embed-container embed {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.embed-container {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%; /* 16/9 ratio */
|
||||
padding-top: 30px; /* IE6 workaround*/
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.embed-container iframe,
|
||||
.embed-container object,
|
||||
.embed-container embed {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
{% endaddtoblock %}
|
||||
|
||||
|
||||
{% addtoblock "js" %}
|
||||
<script src="{{STATIC_URL}}js/bootstrap-datepicker.js"></script>
|
||||
<script src="{{STATIC_URL}}js/bootstrap-datepicker.de.js"></script>
|
||||
{% endaddtoblock %} {% addtoblock "js" %}
|
||||
<script src="{{STATIC_URL}}/js/bootstrap-datepicker.js"></script>
|
||||
<script src="{{STATIC_URL}}/js/bootstrap-datepicker.de.js"></script>
|
||||
<script>
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
var datepicker = $('#calendar').datepicker({
|
||||
minViewMode: 1,
|
||||
endDate: "{% now "SHORT_DATE_FORMAT" %}",
|
||||
format: "dd.mm.yyyy",
|
||||
language: "de",
|
||||
$(document).ready(function(){
|
||||
|
||||
var datepicker = $('#calendar').datepicker({
|
||||
minViewMode: 1,
|
||||
endDate: "{% now "SHORT_DATE_FORMAT" %}",
|
||||
format: "dd.mm.yyyy",
|
||||
language: "de",
|
||||
})
|
||||
|
||||
datepicker.on( "changeDate", function(e){
|
||||
var month = e.date.getMonth() +1
|
||||
window.location ="?month="+month + "&year="+ e.date.getFullYear() ;
|
||||
} );
|
||||
|
||||
$('#new_message_form').submit( function() {
|
||||
if ( $('#message_title').val() == "" ) {
|
||||
alert( "Nachricht hat keinen Titel!");
|
||||
return false;
|
||||
}
|
||||
if ( $('#message_text').val() == "" ) {
|
||||
alert( "Nachricht hat keinen Text!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
datepicker.on( "changeDate", function(e){
|
||||
var month = e.date.getMonth() +1
|
||||
window.location ="?month="+month + "&year="+ e.date.getFullYear() ;
|
||||
} );
|
||||
|
||||
$('#new_message_form').submit( function() {
|
||||
if ( $('#message_title').val() == "" ) {
|
||||
alert( "Nachricht hat keinen Titel!");
|
||||
return false;
|
||||
}
|
||||
if ( $('#message_text').val() == "" ) {
|
||||
alert( "Nachricht hat keinen Text!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
} );
|
||||
|
||||
} );
|
||||
</script>
|
||||
{% endaddtoblock %}
|
||||
|
||||
|
||||
<div id="blog_post">
|
||||
<div class="container">
|
||||
{% if archiveMode %}
|
||||
<h2>Forum Archiv {{month}}/{{year}}</h2>
|
||||
{% else %}
|
||||
<h2>Forum</h2>
|
||||
{% endif %}
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="container">
|
||||
{% if archiveMode %}
|
||||
<h2>Forum Archiv {{month}}/{{year}}</h2>
|
||||
{% else %}
|
||||
<h2>Forum</h2>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="span8">
|
||||
<div class="comments">
|
||||
{% for message in messages %}
|
||||
<div class="comment">
|
||||
<div class="row">
|
||||
|
||||
<div class="span1">
|
||||
<img src="{{MEDIA_URL}}/user_images/{{message.author}}_thumb.png" class="img-circle author_pic">
|
||||
</div>
|
||||
<div class="span7">
|
||||
<div class="name">
|
||||
{{ message.titel }}
|
||||
</div>
|
||||
<div class="date"> {{ message.author.first_name}} am {{message.creation_time}} </div>
|
||||
<div class="response">{{message.text | linebreaks | youtube }}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<div class="comments">
|
||||
{% for message in messages %}
|
||||
<div class="comment">
|
||||
<div class="row">
|
||||
<div class="span1">
|
||||
<img
|
||||
src="{{MEDIA_URL}}/user_images/{{message.author}}_thumb.png"
|
||||
class="img-circle author_pic"
|
||||
/>
|
||||
</div>
|
||||
<div class="span7">
|
||||
<div class="name">{{ message.titel }}</div>
|
||||
<div class="date">
|
||||
{{ message.author.first_name}} am
|
||||
{{message.creation_time}}
|
||||
</div>
|
||||
<div class="response">
|
||||
{{message.text | linebreaks | youtube }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="new_comment" id="new_comment">
|
||||
<h4>Neue Nachricht</h4>
|
||||
<form id="new_message_form" method="post" action="" >
|
||||
{% csrf_token %}
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<input placeholder="Titel / Betreff" id='message_title' name="titel" type="text">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<textarea placeholder="Nachricht" rows="7" id='message_text' name="text"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<input value="Abschicken" class="btn send" type="submit">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- SideBar -->
|
||||
<div class="span3 sidebar offset1">
|
||||
<div class="box" >
|
||||
<h4>Archiv</h4>
|
||||
<div id="calendar" {% if archiveMode %} data-date="01.{{month}}.{{year}}" {% endif %}></div>
|
||||
</div>
|
||||
|
||||
<div class="box2">
|
||||
<a href="#new_comment" >Nachricht schreiben</a><br/>
|
||||
{% if archiveMode %}
|
||||
<a href="." >Aktuelle Nachrichten</a>
|
||||
{% endif%}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="new_comment" id="new_comment">
|
||||
<h4>Neue Nachricht</h4>
|
||||
<form id="new_message_form" method="post" action="">
|
||||
{% csrf_token %}
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<input
|
||||
placeholder="Titel / Betreff"
|
||||
id="message_title"
|
||||
name="titel"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<textarea
|
||||
placeholder="Nachricht"
|
||||
rows="7"
|
||||
id="message_text"
|
||||
name="text"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span8">
|
||||
<input
|
||||
value="Abschicken"
|
||||
class="btn send"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SideBar -->
|
||||
<div class="span3 sidebar offset1">
|
||||
<div class="box">
|
||||
<h4>Archiv</h4>
|
||||
<div id="calendar" {% if archiveMode %}data-date="01.{{month}}.{{year}}"{% endif %}></div>
|
||||
</div>
|
||||
|
||||
<div class="box2">
|
||||
<a href="#new_comment">Nachricht schreiben</a><br />
|
||||
{% if archiveMode %}
|
||||
<a href=".">Aktuelle Nachrichten</a>
|
||||
{% endif%}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,21 +1,36 @@
|
||||
"""
|
||||
Template filter for embedding YouTube videos in forum posts.
|
||||
"""
|
||||
|
||||
import re
|
||||
import django.template
|
||||
|
||||
from django import template
|
||||
from django.template.defaultfilters import stringfilter
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
register = template.Library()
|
||||
|
||||
register = django.template.Library()
|
||||
# Regex to match YouTube URLs
|
||||
YOUTUBE_REGEX = re.compile(
|
||||
r"(?:https://)?(?:http://)?(?:www\.)?youtube\.(?:com|de)/watch\?v=(?P<videoID>[-\w]*)"
|
||||
)
|
||||
|
||||
|
||||
youtubeRegex = re.compile( u'(?:https://)?(?:http://)?www.youtube.(?:com|de)/watch\?v=(?P<videoID>[-\w]*)' )
|
||||
|
||||
@register.filter( name='youtube' )
|
||||
@register.filter(name="youtube")
|
||||
@stringfilter
|
||||
def youtube_filter( value ):
|
||||
replacement = """
|
||||
<div class="embed-container"><iframe src="//www.youtube.de/embed/\g<videoID>" frameborder="0" allowfullscreen></iframe> </div>
|
||||
def youtube_filter(value):
|
||||
"""
|
||||
return mark_safe( youtubeRegex.sub( replacement, value ) )
|
||||
Convert YouTube URLs in text to embedded video iframes.
|
||||
|
||||
|
||||
|
||||
Usage in template:
|
||||
{{ message.text|youtube }}
|
||||
"""
|
||||
replacement = """
|
||||
<div class="embed-container">
|
||||
<iframe src="//www.youtube.com/embed/\\g<videoID>"
|
||||
frameborder="0"
|
||||
allowfullscreen>
|
||||
</iframe>
|
||||
</div>
|
||||
"""
|
||||
return mark_safe(YOUTUBE_REGEX.sub(replacement, value))
|
||||
|
||||
@@ -1,34 +1,55 @@
|
||||
from datetime import datetime
|
||||
from django.shortcuts import render, redirect
|
||||
from simpleforum.models import Message
|
||||
|
||||
from django.shortcuts import redirect, render
|
||||
from django.utils import timezone
|
||||
|
||||
from .models import Message
|
||||
|
||||
|
||||
def message_view(request):
|
||||
if request.method == 'POST':
|
||||
if 'titel' in request.POST and 'text' in request.POST:
|
||||
titel = request.POST.get('titel')
|
||||
text = request.POST.get('text')
|
||||
"""View for displaying and creating forum messages."""
|
||||
|
||||
if len(titel) > 0 and len(text) > 0:
|
||||
Message.objects.create(titel=titel, text=text, author=request.user, creation_time=datetime.now())
|
||||
if request.method == "POST":
|
||||
titel = request.POST.get("titel", "")
|
||||
text = request.POST.get("text", "")
|
||||
|
||||
if titel and text:
|
||||
Message.objects.create(
|
||||
titel=titel,
|
||||
text=text,
|
||||
author=request.user,
|
||||
creation_time=timezone.now(),
|
||||
)
|
||||
|
||||
return redirect(message_view)
|
||||
|
||||
context = dict()
|
||||
context = {}
|
||||
|
||||
if request.method == 'GET':
|
||||
if 'month' in request.GET and 'year' in request.GET:
|
||||
year = int(request.GET['year'])
|
||||
month = int(request.GET['month'])
|
||||
until_date = datetime(year, month + 1, 1)
|
||||
from_date = datetime(year, month, 1)
|
||||
context['archiveMode'] = True
|
||||
context['year'] = year
|
||||
context['month'] = month
|
||||
context['messages'] = Message.objects.filter(creation_time__lt=until_date).filter(
|
||||
creation_time__gte=from_date).order_by('-creation_time')
|
||||
if request.method == "GET":
|
||||
if "month" in request.GET and "year" in request.GET:
|
||||
try:
|
||||
year = int(request.GET["year"])
|
||||
month = int(request.GET["month"])
|
||||
|
||||
from_date = datetime(year, month, 1)
|
||||
# Handle December -> January transition
|
||||
if month == 12:
|
||||
until_date = datetime(year + 1, 1, 1)
|
||||
else:
|
||||
until_date = datetime(year, month + 1, 1)
|
||||
|
||||
context["archiveMode"] = True
|
||||
context["year"] = year
|
||||
context["month"] = month
|
||||
context["messages"] = Message.objects.filter(
|
||||
creation_time__lt=until_date, creation_time__gte=from_date
|
||||
).order_by("-creation_time")
|
||||
except (ValueError, TypeError):
|
||||
# Invalid date parameters, fall back to default view
|
||||
context["messages"] = Message.objects.order_by("-creation_time")[:20]
|
||||
context["archiveMode"] = False
|
||||
else:
|
||||
context['messages'] = Message.objects.order_by('-creation_time')[:20]
|
||||
context['archiveMode'] = False
|
||||
context["messages"] = Message.objects.order_by("-creation_time")[:20]
|
||||
context["archiveMode"] = False
|
||||
|
||||
return render(request, 'simpleforum/simpleforum.html', context)
|
||||
return render(request, "simpleforum/simpleforum.html", context)
|
||||
|
||||
Reference in New Issue
Block a user