add announcement module

This commit is contained in:
doubaniux 2020-12-09 13:47:00 +01:00
parent 31f8a22fb2
commit a1129faffa
50 changed files with 551 additions and 92 deletions

View file

@ -25,6 +25,7 @@ urlpatterns = [
path('users/', include('users.urls')),
path('books/', include('books.urls')),
path('movies/', include('movies.urls')),
path('announcement/', include('management.urls')),
path('', include('common.urls')),
]

View file

@ -12,8 +12,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% trans 'NiceDB - ' %}{{ title }}</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> -->
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
</head>
@ -56,14 +54,14 @@
// when source site is this site, hide url input box and populate it with fake url
// the backend would update this field
if ($("select[name='source_site']").val() == {{ this_site_enum_value }}) {
if ($("select[name='source_site']").val() == "{{ this_site_enum_value }}") {
$("input[name='source_url']").hide();
$("label[for='id_source_url']").hide();
$("input[name='source_url']").val("https://www.temp.com/" + Date.now() + Math.random());
}
$("select[name='source_site']").change(function () {
let value = $(this).val();
if (value == {{ this_site_enum_value }}) {
if (value == "{{ this_site_enum_value }}") {
$("input[name='source_url']").hide();
$("label[for='id_source_url']").hide();
$("input[name='source_url']").val("https://www.temp.com/" + Date.now() + Math.random());

View file

@ -16,8 +16,6 @@
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -15,8 +15,6 @@
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> -->
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
</head>

View file

@ -15,8 +15,6 @@
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> -->
</head>
<body>

View file

@ -27,9 +27,6 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<script src="{% static 'js/detail.js' %}"></script>
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_modal.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
</head>
@ -191,6 +188,7 @@
{% endif %}
<span class="entity-reviews__review-time">{{ others_review.edited_time }}</span>
<span class="entity-reviews__review-title"> <a href="{% url 'books:retrieve_review' others_review.id %}">{{ others_review.title }}</a></span>
<span>{{ others_review.get_plain_content | truncate:100 }}</span>
</li>
{% endfor %}
</ul>

View file

@ -17,8 +17,6 @@
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -20,8 +20,6 @@
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
</head>

View file

@ -17,8 +17,6 @@
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -14,8 +14,6 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'js/scrape.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -1,5 +1,7 @@
import django.contrib.postgres.fields as postgres
import re
from decimal import *
from markdown import markdown
from django.utils.translation import ugettext_lazy as _
from django.db import models, IntegrityError
from django.core.serializers.json import DjangoJSONEncoder
@ -10,6 +12,9 @@ from mastodon.api import get_relationships, get_cross_site_id
from boofilsic.settings import CLIENT_NAME
RE_HTML_TAG = re.compile(r"<[^>]*>")
# abstract base classes
###################################
class SourceSiteEnum(models.TextChoices):
@ -245,6 +250,13 @@ class Review(UserOwnedEntity):
def __str__(self):
return self.title
def get_plain_content(self):
"""
Get plain text format content
"""
html = markdown(self.content)
return RE_HTML_TAG.sub(' ', html)
class Meta:
abstract = True

View file

@ -1,3 +1,4 @@
@import url(https://cdn.jsdelivr.net/npm/skeleton-css@2.0.4/css/normalize.css);
.button,
button,
input[type='button'],
@ -1106,8 +1107,61 @@ select::placeholder {
float: right;
}
.announcement-modal {
z-index: 2;
display: none;
position: fixed;
width: 500px;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
background-color: #f7f7f7;
padding: 20px 20px 10px 20px;
color: #606c76;
}
.announcement-modal .announcement-modal__head {
margin-bottom: 20px;
}
.announcement-modal .announcement-modal__head::after {
content: ' ';
clear: both;
display: table;
}
.announcement-modal .announcement-modal__title {
font-weight: bold;
font-size: 1.2em;
float: left;
}
.announcement-modal .announcement-modal__close-button {
float: right;
cursor: pointer;
}
.announcement-modal .announcement-modal__confirm-button {
float: right;
}
.announcement-modal .announcement-modal__body {
overflow-y: auto;
max-height: 64vh;
}
.announcement-modal .announcement-modal__body .announcement__title {
display: inline-block;
}
.announcement-modal .announcement-modal__body .announcement__datetime {
color: #ccc;
margin-left: 10px;
}
@media (max-width: 575.98px) {
.mark-modal, .confirm-modal {
.mark-modal, .confirm-modal, .announcement-modal {
width: 100%;
}
}
@ -2176,6 +2230,10 @@ select::placeholder {
min-height: 100px;
}
.markdownx-preview ul li {
list-style: circle inside;
}
.rating-star .jq-star {
cursor: unset !important;
}

File diff suppressed because one or more lines are too long

View file

@ -98,9 +98,26 @@
.confirm-modal
@include modal
.announcement-modal
@include modal
& &__body
overflow-y: auto
max-height: 64vh
& .announcement
&__title
display: inline-block
&__datetime
color: $color-light
margin-left: 10px
&__content
// Small devices (landscape phones, 576px and up)
@media (max-width: $small-devices)
.mark-modal, .confirm-modal
.mark-modal, .confirm-modal, .announcement-modal
width: 100%
// Medium devices (tablets, 768px and up)
@media (max-width: $medium-devices)

View file

@ -1,6 +1,9 @@
.markdownx-preview
min-height: 100px
& ul li
list-style: circle inside
.rating-star .jq-star
cursor: unset !important

View file

@ -1,7 +1,7 @@
// Sass Modules
//
@import url(https://cdn.jsdelivr.net/npm/skeleton-css@2.0.4/css/normalize.css)
// milligram
@import Color
// @import Blockquote

View file

@ -5,7 +5,8 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="refresh" content="3;url={% url 'common:home' %}">
<meta http-equiv="refresh" content="3;url={% url 'common:home' %}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/skeleton-css@2.0.4/css/normalize.css">
<link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic_box.css' %}">

View file

@ -20,8 +20,6 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'js/mastodon.js' %}"></script>
<script src="{% static 'js/home.js' %}"></script>
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
</head>
@ -296,6 +294,7 @@
</section>
</div>
{% include "partial/_footer.html" %}
</div>
@ -328,8 +327,63 @@
</div>
</div>
{% if unread_announcements %}
<div id="modals">
<style>
.bottom-link {
margin-top: 30px; text-align: center; margin-bottom: 5px;
}
.bottom-link a {
color: #ccc;
}
</style>
<div class="announcement-modal modal">
<div class="announcement-modal__head">
<h4 class="announcement-modal__title">{% trans '公告' %}</h4>
<span class="announcement-modal__close-button modal-close">
<span class="icon-cross">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<polygon
points="20 2.61 17.39 0 10 7.39 2.61 0 0 2.61 7.39 10 0 17.39 2.61 20 10 12.61 17.39 20 20 17.39 12.61 10 20 2.61">
</polygon>
</svg>
</span>
</span>
</div>
<div class="announcement-modal__body">
<ul>
{% for ann in unread_announcements %}
<li class="announcement">
<a href="{% url 'management:retrieve' ann.pk %}">
<h5 class="announcement__title">{{ ann.title }}</h5>
</a>
<span class="announcement__datetime">{{ ann.created_time }}</span>
<p>{{ ann.content | truncate:200 }}</p>
</li>
{% if not forloop.last %}
<div class="dividing-line" style="border-top-style: dashed;"></div>
{% endif %}
{% endfor %}
</ul>
<div class="bottom-link">
<a href="{% url 'management:list' %}">{% trans '查看全部公告' %}</a>
</div>
</div>
</div>
</div>
<div class="bg-mask"></div>
{% endif %}
<script>
// because the modal and mask elements only exist when there are new announcements
$(".announcement-modal").show();
$(".bg-mask").show();
$(".modal-close").on('click', function () {
$(this).parents(".modal").hide();
$(".bg-mask").hide();
});
</script>
</body>

View file

@ -18,9 +18,7 @@
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -4,7 +4,9 @@
<a class="footer__link" target="_blank" href="https://donotban.com/@whitiewhite">作者长毛象</a>
<a class="footer__link" target="_blank" href="https://github.com/doubaniux/boofilsic/issues">报告错误</a>
<a class="footer__link" target="_blank" href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a>
<a class="footer__link" target="_blank" href="https://patreon.com/tertius" id="githubLink">捐助项目</a>
<a class="footer__link" target="_blank" href="https://patreon.com/tertius" id="sponsor">捐助项目</a>
<a class="footer__link" target="_blank" href="/announcement/supported-sites/" id="supported-sites">支持的网站</a>
<a class="footer__link" href="javascript:void();" id="version">Version 0.2.0</a>
</div>
</div>
</footer>

View file

@ -18,6 +18,7 @@ from mastodon.decorators import mastodon_request_included
from common.models import MarkStatusEnum
from common.utils import PageLinksGenerator
from common.scraper import scraper_registry
from management.models import Announcement
# how many books have in each set at the home page
@ -41,6 +42,11 @@ logger = logging.getLogger(__name__)
def home(request):
if request.method == 'GET':
unread_announcements = Announcement.objects.filter(
pk__gt=request.user.read_announcement_index).order_by('-pk')
request.user.read_announcement_index = Announcement.objects.latest('pk').pk
request.user.save(update_fields=['read_announcement_index'])
do_book_marks = request.user.user_bookmarks.filter(
status=MarkStatusEnum.DO).order_by("-edited_time")
do_books_more = True if do_book_marks.count() > BOOKS_PER_SET else False
@ -86,6 +92,7 @@ def home(request):
'wish_movies_more': wish_movies_more,
'collect_movies_more': collect_movies_more,
'reports': reports,
'unread_announcements': unread_announcements,
}
)
else:

0
management/__init__.py Normal file
View file

4
management/admin.py Normal file
View file

@ -0,0 +1,4 @@
from django.contrib import admin
from .models import *
admin.site.register(Announcement)

5
management/apps.py Normal file
View file

@ -0,0 +1,5 @@
from django.apps import AppConfig
class ManagementConfig(AppConfig):
name = 'management'

39
management/models.py Normal file
View file

@ -0,0 +1,39 @@
import re
from django.db import models
from django.shortcuts import reverse
from django.utils.translation import ugettext_lazy as _
from markdownx.models import MarkdownxField
from markdown import markdown
RE_HTML_TAG = re.compile(r"<[^>]*>")
class Announcement(models.Model):
"""Model definition for Announcement."""
title = models.CharField(max_length=200)
content = MarkdownxField()
slug = models.SlugField(max_length=300, allow_unicode=True, unique=True, null=True, blank=True)
created_time = models.DateTimeField(auto_now_add=True)
edited_time = models.DateTimeField(auto_now_add=True)
class Meta:
"""Meta definition for Announcement."""
verbose_name = 'Announcement'
verbose_name_plural = 'Announcements'
def get_absolute_url(self):
return reverse('management:retrieve', kwargs={'pk': self.pk})
def get_plain_content(self):
"""
Get plain text format content
"""
html = markdown(self.content)
return RE_HTML_TAG.sub(' ', html)
def __str__(self):
"""Unicode representation of Announcement."""
return self.title

View file

@ -0,0 +1,39 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/skeleton-css@2.0.4/css/normalize.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/skeleton-css@2.0.4/css/skeleton.css">
<title>Create/Update Announcement</title>
</head>
<body>
<div class="container">
<style>
textarea {
width: 100%;
min-height: 200px;
}
body {
padding-top: 40px;
}
</style>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save">
</form>
{{ form.media }}
</div>
<script>
function convertToSlug(text) {
// return encodeURI(text.toLowerCase().replace(/ +/g, '-'));
return text.toLowerCase().replace(/ +/g, '-');
}
document.getElementById("id_title").addEventListener('input', function (evt) {
document.getElementById("id_slug").value = convertToSlug(this.value);
});
</script>
</body>
</html>

View file

@ -0,0 +1,24 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/skeleton-css@2.0.4/css/normalize.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/skeleton-css@2.0.4/css/skeleton.css">
<title>Delete Announcement</title>
</head>
<body>
<style>
body {
padding-top: 40px;
}
</style>
<div class="container">
<form method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
<input type="submit" value="Confirm">
</form>
</div>
</body>
</html>

View file

@ -0,0 +1,47 @@
{% load static %}
{% load i18n %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<title>NiceDB - {{ object.title }}</title>
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<div class="grid">
<div class="single-section-wrapper">
<h3>{{ object.title }}</h3>
<div>
{{ object.created_time }} | {{ object.edited_time }}
{% if request.user.is_superuser %}
<span class="operations">
<a href="{% url 'management:delete' object.pk %}">{% trans '删除' %}</a>
<a href="{% url 'management:update' object.pk %}">{% trans '编辑' %}</a>
</span>
{% endif %}
</div>
<div class="dividing-line"></div>
<p>{{ form.content }}</p>
<div style="margin-top: 30px; text-align: center;">
<a href="{% url 'management:list' %}">{% trans '返回公告栏' %}</a>
</div>
{{ form.media }}
</div>
</div>
</div>
{% include "partial/_footer.html" %}
</div>
<script>
document.querySelector(".markdownx textarea").style.display = 'none';
// $(".markdownx textarea").hide();
</script>
</body>
</html>

View file

@ -0,0 +1,120 @@
{% load static %}
{% load i18n %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<title>{% trans 'NiceDB - 公告栏' %}</title>
</head>
<body>
<style>
.markdownx-preview {
min-height: 40px;
}
h4 {
display: inline-block;
}
.operations {
margin-left: 5px;
}
.datetime {
margin-left: 12px;
color: #ccc;
}
.header {
display: inline-block;
}
.add {
margin-left: 15px;
}
.dividing-line {
border-top-style: dashed;
}
</style>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<div class="grid">
<div class="single-section-wrapper">
<h3 class="header">{% trans '公告栏' %}</h3>
<a href="{% url 'management:create' %}" class="add">{% trans '发布新公告' %}</a>
<div style="margin-bottom: 40px;"></div>
<ul>
{% for announcement in object_list %}
<li>
<a href="{{ announcement.get_absolute_url }}"><h4>{{ announcement.title }}</h4></a>
<span class="datetime">{{ announcement.created_time }}</span>
{% if request.user.is_superuser %}
<span class="operations">
<a href="{% url 'management:update' announcement.pk %}">{% trans '编辑' %}</a>
<a href="{% url 'management:delete' announcement.pk %}">{% trans '删除' %}</a>
</span>
{% endif %}
<p>{{ announcement.get_plain_content }}</p>
</li>
{% if not forloop.last %}
<div class="dividing-line"></div>
{% endif %}
{% empty %}
<p>{% trans '暂无公告' %}</p>
{% endfor %}
</ul>
<!-- <div class="pagination">
{% if object_list.pagination.has_prev %}
<a href="?page=1&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}"
class="pagination__nav-link pagination__nav-link">&laquo;</a>
<a href="?page={{ object_list.previous_page_number }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}"
class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">&lsaquo;</a>
{% endif %}
{% for page in object_list.pagination.page_range %}
{% if page == object_list.pagination.current_page %}
<a href="?page={{ page }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}"
class="pagination__page-link pagination__page-link--current">{{ page }}</a>
{% else %}
<a href="?page={{ page }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}"
class="pagination__page-link">{{ page }}</a>
{% endif %}
{% endfor %}
{% if object_list.pagination.has_next %}
<a href="?page={{ object_list.next_page_number }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}"
class="pagination__nav-link pagination__nav-link--left-margin">&rsaquo;</a>
<a href="?page={{ object_list.pagination.last_page }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}"
class="pagination__nav-link">&raquo;</a>
{% endif %}
</div> -->
</div>
</div>
</div>
{% include "partial/_footer.html" %}
</div>
<script>
// hide editing box
document.querySelectorAll(".markdownx textarea").forEach(e => {
e.style.display = 'none';
});
// strip html tags
document.querySelectorAll(".markdownx-preview").forEach(e => {
console.log($(e).text())
$(e).html($(e).text());
});
</script>
</body>
</html>

3
management/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

13
management/urls.py Normal file
View file

@ -0,0 +1,13 @@
from django.urls import path
from .views import *
app_name = 'management'
urlpatterns = [
path('', AnnouncementListView.as_view(), name='list'),
path('<int:pk>/', AnnouncementDetailView.as_view(), name='retrieve'),
path('create/', AnnouncementCreateView.as_view(), name='create'),
path('<str:slug>/', AnnouncementDetailView.as_view(), name='retrieve_slug'),
path('<int:pk>/update/', AnnouncementUpdateView.as_view(), name='update'),
path('<int:pk>/delete/', AnnouncementDeleteView.as_view(), name='delete'),
]

53
management/views.py Normal file
View file

@ -0,0 +1,53 @@
from django.urls import reverse_lazy
from django.shortcuts import get_object_or_404
from .models import Announcement
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required, user_passes_test
from django.views.generic import *
from django.views.generic.edit import ModelFormMixin
from markdown import markdown
import re
# https://docs.djangoproject.com/en/3.1/topics/class-based-views/intro/
decorators = [login_required, user_passes_test(lambda u: u.is_superuser)]
class AnnouncementDetailView(DetailView, ModelFormMixin):
model = Announcement
fields = ['content']
template_name = "management/detail.html"
class AnnouncementListView(ListView):
model = Announcement
# paginate_by = 1
template_name = "management/list.html"
@method_decorator(decorators, name='dispatch')
class AnnouncementDeleteView(DeleteView):
model = Announcement
success_url = reverse_lazy("management:list")
template_name = "management/delete.html"
@method_decorator(decorators, name='dispatch')
class AnnouncementCreateView(CreateView):
model = Announcement
fields = '__all__'
template_name = "management/create_update.html"
@method_decorator(decorators, name='dispatch')
class AnnouncementUpdateView(UpdateView):
model = Announcement
fields = '__all__'
template_name = "management/create_update.html"
def form_valid(self, form):
form.instance.edited_time = timezone.now()
return super().form_valid(form)

View file

@ -105,6 +105,7 @@ def create_app(domain_name):
from boofilsic.settings import DEBUG
if DEBUG:
payload['redirect_uris'] = 'http://localhost/users/OAuth2_login/\nurn:ietf:wg:oauth:2.0:oob'
payload['client_name'] = 'test_do_not_authorise'
response = post(url, data=payload)
return response

View file

@ -12,8 +12,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% trans 'NiceDB - ' %}{{ title }}</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> -->
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
</head>
@ -21,7 +19,7 @@
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<section id="content" class="container">
<div class="grid">
<div class="single-section-wrapper" id="main">
@ -31,7 +29,7 @@
{% csrf_token %}
{{ form.media }}
{% for field in form %}
{% if field.id_for_label == 'id_is_series' %}
<label for="{{ field.id_for_label }}"
style="display: inline-block; position: relative;">{{ field.label }}</label>
@ -42,43 +40,42 @@
{% endif %}
{{ field }}
{% endif %}
{% endfor %}
<input class="button" type="submit" value="{% trans '提交' %}">
</form>
</div>
</section>
</div>
{% include "partial/_footer.html" %}
</div>
{% comment %}
{% comment %}
<div id="oauth2Token" hidden="true">{% oauth_token %}</div>
<div id="mastodonURI" hidden="true">{% mastodon request.user.mastodon_site %}</div>
<!--current user mastodon id-->
<!--current user mastodon id-->
<div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div>
{% endcomment %}
<script>
// mark required
$("#content *[required]").each(function () {
$(this).prev().prepend("*");
});
// when source site is this site, hide url input box and populate it with fake url
// the backend would update this field
if ($("select[name='source_site']").val() == {{ this_site_enum_value }}) {
$("input[name='source_url']").hide();
$("label[for='id_source_url']").hide();
$("input[name='source_url']").val("https://www.temp.com/" + Date.now() + Math.random());
}
$("select[name='source_site']").change(function () {
let value = $(this).val();
if (value == {{ this_site_enum_value }
}) {
<script>
// mark required
$("#content *[required]").each(function () {
$(this).prev().prepend("*");
});
// when source site is this site, hide url input box and populate it with fake url
// the backend would update this field
if ($("select[name='source_site']").val() == "{{ this_site_enum_value }}") {
$("input[name='source_url']").hide();
$("label[for='id_source_url']").hide();
$("input[name='source_url']").val("https://www.temp.com/" + Date.now() + Math.random());
}
$("select[name='source_site']").change(function () {
let value = $(this).val();
if (value == "{{ this_site_enum_value }}") {
$("input[name='source_url']").hide();
$("label[for='id_source_url']").hide();
$("input[name='source_url']").val("https://www.temp.com/" + Date.now() + Math.random());
@ -88,9 +85,9 @@
$("input[name='source_url']").val("");
}
});
</script>
</body>
</html>
</html>

View file

@ -18,8 +18,6 @@
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -17,8 +17,6 @@
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> -->
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
</head>

View file

@ -12,11 +12,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% trans 'NiceDB - 删除评论' %}</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> -->
</head>
<body>

View file

@ -38,11 +38,9 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<script src="{% static 'js/detail.js' %}"></script>
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_modal.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.css' %}">
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
</head>
<body>
@ -305,6 +303,7 @@
{% endif %}
<span class="entity-reviews__review-time">{{ others_review.edited_time }}</span>
<span class="entity-reviews__review-title"> <a href="{% url 'movies:retrieve_review' others_review.id %}">{{ others_review.title }}</a></span>
<span>{{ others_review.get_plain_content | truncate:100 }}</span>
</li>
{% endfor %}
</ul>

View file

@ -19,8 +19,6 @@
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -22,8 +22,6 @@
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
</head>

View file

@ -19,8 +19,6 @@
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -14,8 +14,6 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'js/scrape.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -20,6 +20,9 @@ class User(AbstractUser):
mastodon_id = models.IntegerField(blank=False)
# mastodon domain name, eg donotban.com
mastodon_site = models.CharField(max_length=100, blank=False)
# store the latest read announcement id,
# every time user read the announcement update this field
read_announcement_index = models.PositiveIntegerField(default=0)
class Meta:
constraints = [

View file

@ -19,8 +19,6 @@
<script src="{% static 'js/home.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -10,12 +10,11 @@
<meta property="og:type" content="website">
<meta property="og:url" content="{{ request.build_absolute_uri }}">
<meta property="og:image" content="{{ request.scheme }}://{{ request.get_host }}{% static 'img/logo_square.jpg' %}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/skeleton-css@2.0.4/css/normalize.css">
<link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic_box.css' %}">
<!-- <link rel="stylesheet" href="{% static 'lib/css/chosen.min.css' %}"> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- <script src="{% static 'lib/js/chosen.jquery.min.js' %}"></script> -->
<script src="{% static 'lib/js/js.cookie.min.js' %}"></script>
<title>{% trans 'NiceDB - 登录' %}</title>
</head>

View file

@ -14,8 +14,6 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'js/create_update.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> -->
</head>
<body>

View file

@ -21,8 +21,6 @@
<script src="{% static 'js/home.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>

View file

@ -6,6 +6,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/skeleton-css@2.0.4/css/normalize.css">
<link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic_box.css' %}">

View file

@ -23,8 +23,7 @@
{% else %}
<script src="{% static 'js/following_list.js' %}"></script>
{% endif %}
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> -->
<!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
</head>

View file

@ -14,8 +14,6 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{% static 'js/create_update.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}">
<link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -->
</head>
<body>