diff --git a/react/src/dashboard.js b/react/src/dashboard.js index 3b8431e1d498e90aca922ffa13e9ce91f9c21bac..7ecf67c9ccb2cc3b7d0fe04f7929d0028d341a9f 100644 --- a/react/src/dashboard.js +++ b/react/src/dashboard.js @@ -45,28 +45,45 @@ class Dashboard extends React.Component { } closeNotification(notification) { - + console.log(notification); + $("#not-" + notification.id).addClass("scale-out"); + window.setTimeout(() => { + $("#not-" + notification.id).remove(); + }, 200); + $.getJSON(API_URL + "/notifications/read/" + notification.id); + this.updateData(); + this.setState({time: new Date()}); } render() { + const that = this; return <div> <button className={"btn-flat right grey-text"} onClick={this.updateData}> <i className={"material-icons left"}>refresh</i> in {this.state.refreshIn} s </button> <p className="flow-text">Willkommen bei SchoolApps!</p> - <div className={"alert primary"}> - <div> - <i className={"material-icons left"}>info</i> - <button className={"btn-flat right"}><i className={"material-icons center"}>close</i></button> - <strong>Ihr Antrag auf Unterrichtsbefreiung wurde genehmigt</strong> - <p>Ihr Antrag auf Unterrichtsbefreiung vom 20. August 2019, 08:45 Uhr bis 29. August 2019, 13:10 Uhr - wurde von der Schulleitung genehmigt. </p> - </div> - </div> + {this.state.unread_notifications && this.state.unread_notifications.length > 0 ? + this.state.unread_notifications.map(function (notification) { + return <div className={"alert primary scale-transition"} id={"not-" + notification.id} + key={notification.id}> + <div> + <i className={"material-icons left"}>info</i> + <div className={"right"}> + <button className={"btn-flat"} onClick={() => that.closeNotification(notification)}> + <i className={"material-icons center"}>close</i> + {/*Gelesen*/} + </button> + </div> + <strong>{notification.title}</strong> + <p>{notification.description}</p> + </div> + </div>; + }) : ""} + <div className={"row"}> - <div className={"col s12 m8"}> - <div className="col s12 m6"> + <div className={"col s12 m6 l6 xl8 no-padding"}> + <div className="col s12 m12 l12 xl6"> <div className="card"> <div className="card-content"> <span className="card-title">Vertretungen der <em>Eb</em> für heute</span> @@ -81,7 +98,7 @@ class Dashboard extends React.Component { </div> </div> </div> - <div className="col s12 m6"> + <div className="col s12 m12 l12 xl6"> <div className="card"> <div className="card-content"> <span className="card-title">Aktuelle Termine</span> @@ -103,7 +120,7 @@ class Dashboard extends React.Component { </div> - <div className="col s12 m6"> + <div className="col s12 m12 l12 xl6"> <div className="card"> <div className="card-content"> <span className="card-title">Mein Status</span> @@ -134,7 +151,7 @@ class Dashboard extends React.Component { </div> - <div className="col s12 m6"> + <div className="col s12 m12 l12 xl6"> <div className="card"> <div className="card-content"> <span className="card-title">Klausuren der <em>Eb</em></span> @@ -156,22 +173,27 @@ class Dashboard extends React.Component { </div> </div> - <div className="col s12 m4"> + {this.state.newest_article ? <div className="col s12 m6 l6 xl4"> <div className="card"> <div className="card-image"> - <img - src="https://katharineum-zu-luebeck.de/wp-content/uploads/2019/08/E969562D-C413-4B18-AC63-26C768499BFF.jpeg"/> - <span className="card-title">Ein großer Tag - Die Einschulung der neuen Sextaner</span> + <span className={"badge-image"}>Aktuelles von der Homepage</span> + <img src={this.state.newest_article.image_url} alt={this.state.newest_article.title}/> + <span className="card-title" + dangerouslySetInnerHTML={{__html: this.state.newest_article.title}}/> </div> <div className="card-content"> - <p>Am 13.08. war es wieder so weit: am Katharineum wurden die neuen Sextaner willkommen - geheißen. Bereits zehn Minuten vor Beginn der alljährlichen Veranstaltung war die…</p> + <p dangerouslySetInnerHTML={{__html: this.state.newest_article.short_text}}/> </div> <div className="card-action"> - <a href="#">Mehr lesen</a> + <a href={this.state.newest_article.link} target={"_blank"}>Mehr lesen</a> </div> </div> - </div> + <a className={"btn hundred-percent primary-color"} href={"https://katharineum-zu-luebeck.de/"} + target={"_blank"}> + Weitere Artikel + <i className={"material-icons right"}>arrow_forward</i> + </a> + </div> : ""} </div> <div className={"row"}> diff --git a/schoolapps/dashboard/models.py b/schoolapps/dashboard/models.py index 218eb4e438c3937989dc9fb9dd532323a0467168..b9eddcc927d48239e5ebf47cefaca8da8b900faa 100755 --- a/schoolapps/dashboard/models.py +++ b/schoolapps/dashboard/models.py @@ -35,6 +35,7 @@ class Notification(models.Model): app = models.CharField(max_length=100) + read = models.BooleanField(default=False) created_at = models.DateTimeField(default=timezone.now) def __str__(self): diff --git a/schoolapps/dashboard/urls.py b/schoolapps/dashboard/urls.py index 57ba03b19fde876018f67d960ec08835d2037dae..3f7dee498724bf928c2824c1a6f099b275bcd5a3 100755 --- a/schoolapps/dashboard/urls.py +++ b/schoolapps/dashboard/urls.py @@ -4,5 +4,6 @@ from . import views urlpatterns = [ path('', views.index, name='dashboard'), path('api', views.api_information, name="api_information"), + path('api/notifications/read/<int:id>', views.api_read_notification, name="api_read_notification"), path('test/', views.test_notification, name='test'), ] diff --git a/schoolapps/dashboard/views.py b/schoolapps/dashboard/views.py index 6421684e3462e8f2866e60d2be32df685b634497..f258e37b373404043da21ec170d9665891fcdc98 100755 --- a/schoolapps/dashboard/views.py +++ b/schoolapps/dashboard/views.py @@ -1,8 +1,10 @@ from django.contrib.auth.decorators import login_required from django.http import JsonResponse -from django.shortcuts import render, redirect +from django.shortcuts import render, redirect, get_object_or_404 from django.urls import reverse -from .models import Activity, register_notification + +from helper import get_newest_articles +from .models import Activity, register_notification, Notification # from .apps import DashboardConfig from mailer import send_mail_with_template from userinformation import UserInformation @@ -13,30 +15,8 @@ from userinformation import UserInformation @login_required def index(request): """ Index page: Lists activities und notifications """ - # Register visit - # act = Activity(title="Dashboard aufgerufen", description="Sie haben das Dashboard aufgerufen.", - # app=DashboardConfig.verbose_name, user=request.user) - # act.save() - print(request.user) - # UserInformation.user_classes(request.user) - print(UserInformation.user_courses(request.user)) - # Load activities - activities = Activity.objects.filter(user=request.user).order_by('-created_at')[:5] - - # Load notifications - notifications = request.user.notifications.all().filter(user=request.user).order_by('-created_at')[:5] - - # user_type = UserInformation.user_type(request.user) context = { - 'activities': activities, - 'notifications': notifications, - 'user_type': UserInformation.user_type(request.user), - 'user_type_formatted': UserInformation.user_type_formatted(request.user), - 'classes': UserInformation.user_classes(request.user), - 'courses': UserInformation.user_courses(request.user), - 'subjects': UserInformation.user_subjects(request.user), - 'has_wifi': UserInformation.user_has_wifi(request.user) } return render(request, 'dashboard/index.html', context) @@ -49,22 +29,39 @@ def api_information(request): # Load notifications notifications = request.user.notifications.all().filter(user=request.user).order_by('-created_at')[:5] - + unread_notifications = request.user.notifications.all().filter(user=request.user, read=False).order_by( + '-created_at') # user_type = UserInformation.user_type(request.user) + newest_articles = get_newest_articles("https://katharineum-zu-luebeck.de", 1, [22]) + if len(newest_articles) >= 0: + newest_article = newest_articles[0] + else: + newest_article = None + print(newest_articles) context = { 'activities': list(activities.values()), 'notifications': list(notifications.values()), + "unread_notifications": list(unread_notifications.values()), 'user_type': UserInformation.user_type(request.user), 'user_type_formatted': UserInformation.user_type_formatted(request.user), 'classes': UserInformation.user_classes(request.user), 'courses': UserInformation.user_courses(request.user), 'subjects': UserInformation.user_subjects(request.user), - 'has_wifi': UserInformation.user_has_wifi(request.user) + 'has_wifi': UserInformation.user_has_wifi(request.user), + "newest_article": newest_article, } print(context) return JsonResponse(context) +@login_required +def api_read_notification(request, id): + notification = get_object_or_404(Notification, id=id, user=request.user) + notification.read = True + notification.save() + return JsonResponse({"success": True}) + + @login_required def test_notification(request): """ Sends a test mail """ diff --git a/schoolapps/helper.py b/schoolapps/helper.py index 04b910255cffad5db90f9c4077b9016a21ae5b82..6c15383008e7cfd80f0f0ddb69b1140ea10e4445 100644 --- a/schoolapps/helper.py +++ b/schoolapps/helper.py @@ -20,3 +20,48 @@ def path_and_rename(instance, filename): @register.inclusion_tag("components/msgbox.html") def msg_box(msg, status="success", icon="info"): return {"msg": msg, "status": status, "icon": icon} + + +import requests + + +def get_newest_articles(domain, limit=0, author_blacklist=None): + """ + This function returns the newest articles/posts of a wordpress-site. + + :param domain: The domain to get the newest posts from (for example https://wordpress.com). Don't put a slash (/) at the end! + :param limit: if 0: all posts will be shown, else nly the certain number + :param author_blacklist: if the authors id (an integer) is in this list, the article won't be displayed + :return: a list of the newest posts/articles + """ + if author_blacklist is None: + author_blacklist = [] + + suffix = "/wp-json/wp/v2/posts" + + url = domain + suffix + + site = requests.get(url) + data = site.json() + + posts = [] + print(data) + for post in data: + if post["author"] not in author_blacklist: + # Now get the link to the image + if post["_links"].get("wp:featuredmedia", False): + media_site = requests.get(post["_links"]["wp:featuredmedia"][0]["href"]).json() + image_url = media_site["guid"]["rendered"] + + posts.append( + { + "title": post["title"]["rendered"], + "short_text": post["excerpt"]["rendered"], + "link": post["link"], + "image_url": image_url, + } + ) + if len(posts) >= limit and limit >= 0: + break + + return posts diff --git a/schoolapps/static/common/style.css b/schoolapps/static/common/style.css index 765fe7ea2951d6a45a9b11ab805dde7ec088b920..dcdc1ae1bf795c3dc6c9ffaa5ef84c7607d67551 100755 --- a/schoolapps/static/common/style.css +++ b/schoolapps/static/common/style.css @@ -399,7 +399,7 @@ table.striped > tbody > tr:nth-child(odd) { } .alert.primary p, .alert.primary div { - background-color: #eca4af; + background-color: #ececec; border-color: #da1f3d; } @@ -517,6 +517,10 @@ i.collapsible-trigger { margin: 0 !important; } +.no-padding { + padding: 0 !important; +} + .no-pad-left { padding-left: 0 !important; } @@ -577,4 +581,21 @@ i.collapsible-trigger { flex-wrap: wrap; align-items: center; justify-content: space-between; +} + +.hundred-percent { + width: 100%; +} + +.badge-image { + position: absolute; + left: 0; + top: 10px; + z-index: 1; + background-color: #da1f3d; + color: white; + padding: 2px 10px; + border-radius: 0 3px 3px 0; + text-transform: uppercase; + font-weight: 300; } \ No newline at end of file diff --git a/schoolapps/static/js/dashboard.js b/schoolapps/static/js/dashboard.js index aed9faa95005af45c2d11aaf987ad8004fd91920..c4744471243f5d70dda0fb161f5b2f921e32af25 100644 --- a/schoolapps/static/js/dashboard.js +++ b/schoolapps/static/js/dashboard.js @@ -106,10 +106,19 @@ var Dashboard = function (_React$Component) { }, { key: "closeNotification", value: function closeNotification(notification) { + console.log(notification); + $("#not-" + notification.id).addClass("scale-out"); + window.setTimeout(function () { + $("#not-" + notification.id).remove(); + }, 200); + $.getJSON(API_URL + "/notifications/read/" + notification.id); + this.updateData(); + this.setState({time: new Date()}); } }, { key: "render", value: function render() { + var that = this; return React.createElement( "div", null, @@ -130,47 +139,60 @@ var Dashboard = function (_React$Component) { {className: "flow-text"}, "Willkommen bei SchoolApps!" ), - React.createElement( - "div", - {className: "alert primary"}, - React.createElement( + this.state.unread_notifications && this.state.unread_notifications.length > 0 ? this.state.unread_notifications.map(function (notification) { + return React.createElement( "div", - null, - React.createElement( - "i", - {className: "material-icons left"}, - "info" - ), + { + className: "alert primary scale-transition", id: "not-" + notification.id, + key: notification.id + }, React.createElement( - "button", - {className: "btn-flat right"}, + "div", + null, React.createElement( "i", - {className: "material-icons center"}, - "close" + {className: "material-icons left"}, + "info" + ), + React.createElement( + "div", + {className: "right"}, + React.createElement( + "button", + { + className: "btn-flat", onClick: function onClick() { + return that.closeNotification(notification); + } + }, + React.createElement( + "i", + {className: "material-icons center"}, + "close" + ) + ) + ), + React.createElement( + "strong", + null, + notification.title + ), + React.createElement( + "p", + null, + notification.description ) - ), - React.createElement( - "strong", - null, - "Ihr Antrag auf Unterrichtsbefreiung wurde genehmigt" - ), - React.createElement( - "p", - null, - "Ihr Antrag auf Unterrichtsbefreiung vom 20. August 2019, 08:45 Uhr bis 29. August 2019, 13:10 Uhr wurde von der Schulleitung genehmigt. " ) - ) - ), + ); + }) : "", React.createElement( "div", {className: "row"}, React.createElement( "div", - {className: "col s12 m8"}, + {className: "col s12 m6 l6 xl8 no-padding"}, React.createElement( "div", - {className: "col s12 m6"}, + {className: "col s12 m12 l12 xl6"}, React.createElement( "div", {className: "card"}, @@ -212,7 +234,7 @@ var Dashboard = function (_React$Component) { ), React.createElement( "div", - {className: "col s12 m6"}, + {className: "col s12 m12 l12 xl6"}, React.createElement( "div", {className: "card"}, @@ -260,7 +282,7 @@ var Dashboard = function (_React$Component) { ), React.createElement( "div", - {className: "col s12 m6"}, + {className: "col s12 m12 l12 xl6"}, React.createElement( "div", {className: "card"}, @@ -318,7 +340,7 @@ var Dashboard = function (_React$Component) { ), React.createElement( "div", - {className: "col s12 m6"}, + {className: "col s12 m12 l12 xl6"}, React.createElement( "div", {className: "card"}, @@ -370,44 +392,59 @@ var Dashboard = function (_React$Component) { ) ) ), - React.createElement( + this.state.newest_article ? React.createElement( "div", - {className: "col s12 m4"}, + {className: "col s12 m6 l6 xl4"}, React.createElement( "div", {className: "card"}, React.createElement( "div", {className: "card-image"}, - React.createElement("img", { - src: "https://katharineum-zu-luebeck.de/wp-content/uploads/2019/08/E969562D-C413-4B18-AC63-26C768499BFF.jpeg" - }), React.createElement( "span", - {className: "card-title"}, - "Ein gro\xDFer Tag - Die Einschulung der neuen Sextaner" - ) + {className: "badge-image"}, + "Aktuelles von der Homepage" + ), + React.createElement("img", { + src: this.state.newest_article.image_url, + alt: this.state.newest_article.title + }), + React.createElement("span", { + className: "card-title", + dangerouslySetInnerHTML: {__html: this.state.newest_article.title} + }) ), React.createElement( "div", {className: "card-content"}, - React.createElement( - "p", - null, - "Am 13.08. war es wieder so weit: am Katharineum wurden die neuen Sextaner willkommen gehei\xDFen. Bereits zehn Minuten vor Beginn der allj\xE4hrlichen Veranstaltung war die\u2026" - ) + React.createElement("p", {dangerouslySetInnerHTML: {__html: this.state.newest_article.short_text}}) ), React.createElement( "div", {className: "card-action"}, React.createElement( "a", - {href: "#"}, + {href: this.state.newest_article.link, target: "_blank"}, "Mehr lesen" ) ) + ), + React.createElement( + "a", + { + className: "btn hundred-percent primary-color", + href: "https://katharineum-zu-luebeck.de/", + target: "_blank" + }, + "Weitere Artikel", + React.createElement( + "i", + {className: "material-icons right"}, + "arrow_forward" + ) ) - ) + ) : "" ), React.createElement( "div",