diff --git a/BaseModels/base_models.py b/BaseModels/base_models.py index a92eb26..21b5a4a 100644 --- a/BaseModels/base_models.py +++ b/BaseModels/base_models.py @@ -112,6 +112,20 @@ class BaseModelViewPage(BaseModel): class Meta: abstract = True + def get_title(self): + if self.seo_title: + return self.seo_title + elif self.title: + return self.title + else: + return self.name + + def get_description(self): + if self.seo_description: + return self.seo_description + else: + return self.description + def get_FAQ_items(self): return self.FAQ_items.filter(enable=True).order_by('order') diff --git a/GeneralApp/funcs.py b/GeneralApp/funcs.py index 983fc4b..815796f 100644 --- a/GeneralApp/funcs.py +++ b/GeneralApp/funcs.py @@ -1,14 +1,38 @@ from django.http import HttpResponse, Http404, FileResponse +from django.conf import settings def get_inter_Dict(user): from SubscribesApp.funcs import get_cur_user_subscribe user_subscribe = get_cur_user_subscribe(user) - return {'user_subscribe': user_subscribe} + Dict = { + 'user_subscribe': user_subscribe, + } + from PushMessages.views import get_key_Dict + Dict.update(get_key_Dict()) + + return Dict def get_inter_http_respose(template_obj, context_Dict, request): context_Dict.update(get_inter_Dict(request.user)) + from PushMessages.views import send_push + if request and 'page' in context_Dict: + text = None + title = None + + if context_Dict['page'] == dict: + if 'title' in context_Dict['page']: + title = context_Dict['page']['title'] + if 'description' in context_Dict['page']: + text = context_Dict['page']['description'] + else: + title = getattr(context_Dict['page'], 'title', None) + text = getattr(context_Dict['page'], 'description', None) + + if text and title and not request.user.is_anonymous: + send_push(user=request.user, title=title, text=text) + return HttpResponse(template_obj.render(context_Dict, request)) \ No newline at end of file diff --git a/GeneralApp/views.py b/GeneralApp/views.py index 779efda..9af48ce 100644 --- a/GeneralApp/views.py +++ b/GeneralApp/views.py @@ -6,33 +6,64 @@ from django.contrib.auth.decorators import login_required from .models import * from django.conf import settings from .funcs import get_inter_http_respose +from django.http.response import JsonResponse, HttpResponse +from django.views.decorators.http import require_GET, require_POST +from django.shortcuts import get_object_or_404 +from django.contrib.auth.models import User +from django.views.decorators.csrf import csrf_exempt +from webpush import send_user_notification +import json def test_code(request): from RoutesApp.funcs import get_city_by_type_transport_and_address_point from RoutesApp.models import Route from ReferenceDataApp.models import Airport, City - routes = Route.objects.all() + try: + # body = request.body + # data = json.loads(body) + # if 'head' not in data or 'body' not in data or 'id' not in data: + # return JsonResponse(status=400, data={"message": "Invalid data format"}) + # user_id = data['id'] + user = request.user + payload = {'head': '123', 'body': 'qwerty'} + send_user_notification(user=user, payload=payload, ttl=1000) + return JsonResponse(status=200, data={"message": "Web push successful"}) + except TypeError: + return JsonResponse(status=500, data={"message": "An error occurred"}) - for route in routes: - print(route.id) - required_save = False - if not route.from_city: - route.from_city = get_city_by_type_transport_and_address_point(route.type_transport, route.from_address_point) - required_save = True + # routes = Route.objects.all() + # + # for route in routes: + # print(route.id) + # required_save = False + # if not route.from_city: + # route.from_city = get_city_by_type_transport_and_address_point(route.type_transport, route.from_address_point) + # required_save = True + # + # if not route.to_city: + # route.to_city = get_city_by_type_transport_and_address_point(route.type_transport, + # route.to_address_point) + # required_save = True + # + # if required_save: + # route.save() - if not route.to_city: - route.to_city = get_city_by_type_transport_and_address_point(route.type_transport, - route.to_address_point) - required_save = True - - if required_save: - route.save() - - return HttpResponse('finished') + # return HttpResponse('finished') +def Page404(request, exeption=None): + + Dict = {} + + t = loader.get_template('404.html') + try: + res = get_inter_http_respose(t, Dict, request) + return HttpResponse(res, status=404) + except Exception as e: + return HttpResponse(str(e)) + @@ -58,6 +89,8 @@ def MainPage(request): 'owner_type': 'mover' } + + breadcrumbs_Dict = { } Dict.update({'breadcrumbs': breadcrumbs_Dict}) diff --git a/PushMessages/__init__.py b/PushMessages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/PushMessages/admin.py b/PushMessages/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/PushMessages/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/PushMessages/apps.py b/PushMessages/apps.py new file mode 100644 index 0000000..7034e70 --- /dev/null +++ b/PushMessages/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PushmessagesConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'PushMessages' diff --git a/PushMessages/migrations/__init__.py b/PushMessages/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/PushMessages/models.py b/PushMessages/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/PushMessages/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/PushMessages/tests.py b/PushMessages/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/PushMessages/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/PushMessages/urls.py b/PushMessages/urls.py new file mode 100644 index 0000000..961d48c --- /dev/null +++ b/PushMessages/urls.py @@ -0,0 +1,16 @@ +# coding=utf-8 +from django.urls import path, include +# from AuthApp.js_views import * +# from AuthApp.import_funcs import * +from .views import * +from django.contrib.auth import views +from RoutesApp.js_views import new_route_view_ajax +from django.views.generic import TemplateView + +urlpatterns = [ + + path('send_push', send_push), + path('webpush/', include('webpush.urls')), + path('sw.js', TemplateView.as_view(template_name='sw.js', content_type='application/x-javascript')), + +] \ No newline at end of file diff --git a/PushMessages/views.py b/PushMessages/views.py new file mode 100644 index 0000000..39889d2 --- /dev/null +++ b/PushMessages/views.py @@ -0,0 +1,39 @@ +from django.http.response import JsonResponse, HttpResponse +from django.views.decorators.http import require_GET, require_POST +from django.contrib.auth.models import User +from django.views.decorators.csrf import csrf_exempt +from webpush import send_user_notification +import json +from django.shortcuts import render, get_object_or_404 +from django.conf import settings + + +def get_key_Dict(): + webpush_settings = getattr(settings, 'WEBPUSH_SETTINGS', {}) + vapid_key = webpush_settings.get('VAPID_PUBLIC_KEY') + Dict = { + 'vapid_key': vapid_key + } + return Dict + +def send_push(user, title, text, img=None): + try: + # body = request.body + # data = json.loads(body) + # + # if 'head' not in data or 'body' not in data or 'id' not in data: + # return JsonResponse(status=400, data={"message": "Invalid data format"}) + # + # user_id = data['id'] + # user = get_object_or_404(User, pk=user_id) + Dict = { + 'head': title, + 'body': text + } + + # payload = {'head': data['head'], 'body': data['body']} + send_user_notification(user=user, payload=Dict, ttl=1000) + + return JsonResponse(status=200, data={"message": "Web push successful"}) + except TypeError: + return JsonResponse(status=500, data={"message": "An error occurred"}) diff --git a/TWB/settings.py b/TWB/settings.py index a3f8576..501f6c5 100644 --- a/TWB/settings.py +++ b/TWB/settings.py @@ -28,6 +28,14 @@ DEBUG = True ALLOWED_HOSTS = ["*"] +WEBPUSH_SETTINGS = { + "VAPID_PUBLIC_KEY": "BKS8byh3MucwCF2h06JY9oey1s1RYII09j-j3ehI3qTYhs965UHv0qNPl-jFjQBbIJCvjVXm9RW6t_oJJK8yMOk", + "VAPID_PRIVATE_KEY": "f5NMgOntBtRqsyeKwEzloK-051ggMnZGF_GFimERY0w", + "VAPID_ADMIN_EMAIL": "admin@tripwb.com" +} + +# NOTIFICATION_KEY = 'BJLyGzmo8sLI3Qkc6pN2cz11frCXiJdewvgve7Yps-_fM1lY1LSnTQfQxYtAgQ_26nAji_rgeYC1DkLiTwxw0Mo' + # SESSION_COOKIE_HTTPONLY = False # Application definition @@ -51,12 +59,15 @@ INSTALLED_APPS = [ 'ckeditor', 'ckeditor_uploader', + 'webpush', + 'GeneralApp', 'AuthApp', 'RoutesApp', 'ReferenceDataApp', 'ArticlesApp', 'SubscribesApp', + 'PushMessages', ] MIDDLEWARE = [ diff --git a/TWB/urls.py b/TWB/urls.py index 9d27d8e..c772353 100644 --- a/TWB/urls.py +++ b/TWB/urls.py @@ -3,12 +3,17 @@ from django.contrib import admin from django.urls import path, include from django.conf.urls.static import static from django.conf import settings +from GeneralApp.views import Page404 + +handler404 = Page404 urlpatterns = [ # path('admin/', admin.site.urls), path('ckeditor/', include('ckeditor_uploader.urls')), path('i18n/', include('django.conf.urls.i18n')), + # path('webpush/', include('webpush.urls')), + path('messages/', include('ChatServiceApp.urls')), path('user_account/', include('AuthApp.js_urls')), @@ -22,6 +27,10 @@ urlpatterns = [ path('reference_data/', include('ReferenceDataApp.js_urls')), path('', include('ArticlesApp.js_urls')), + + path('test_404', Page404, name='page_404'), + + path('', include('PushMessages.urls')) ] from django.conf.urls.i18n import i18n_patterns diff --git a/requirements.pip b/requirements.pip index abb2b5c..618a0c6 100644 --- a/requirements.pip +++ b/requirements.pip @@ -10,4 +10,5 @@ channels==4.0.0 daphne==4.0.0 channels-redis==4.1.0 django-colorfield +django-webpush==0.3.5 diff --git a/static/css/styles(boris).css b/static/css/styles(boris).css index 69f3aab..51c8f8b 100644 --- a/static/css/styles(boris).css +++ b/static/css/styles(boris).css @@ -1240,7 +1240,7 @@ .not_found_routes{ width: 96%; - height: 250px; + min-height: 250px; background: #FFFFFF; box-shadow: -1px 4px 10px 0 rgba(198, 199, 203, 0.20), 0 -1px 10px 0 rgba(198, 199, 203, 0.20); position: relative; diff --git a/static/css/styles.css b/static/css/styles.css index 62d653c..a42f711 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -773,6 +773,20 @@ span.btn_profile_name { display: block; } +#create_route{ + border-radius: 10px; + color: #FFFFFF; + background: #FF613A; + /*height: 60px;*/ + font-size: 18px; + font-weight: 500; + width: 100%; + margin-top: 10px; + display: inline-block; + + padding: 15px 0px; +} + /* Change color of dropdown links on hover */ .dropdown-content-lang a:hover {background-color: #f1f1f1} @@ -2056,6 +2070,26 @@ button.cancel_remove.show, button.confirm_remove.show{ /*Static_pages*/ + +.not_found_wrap{ + padding-top: 20px; +} + +.not_found_text{ + text-align: center; + + font-style: normal; + font-weight: 700; + line-height: 52px; + margin-bottom: 20px; +} +.not_found_title{ + font-size: 60px; +} +.not_found_sub_title{ + font-size: 26px; +} + #title_static{ text-align: center; font-size: 44px; diff --git a/static/js/push/registerSw.js b/static/js/push/registerSw.js new file mode 100644 index 0000000..1220512 --- /dev/null +++ b/static/js/push/registerSw.js @@ -0,0 +1,91 @@ +const registerSw = async () => { + if ('serviceWorker' in navigator) { + const reg = await navigator.serviceWorker.register('/sw.js'); + initialiseState(reg) + + } else { + showNotAllowed("You can't send push notifications ☹️😢") + } +}; + +const initialiseState = (reg) => { + if (!reg.showNotification) { + showNotAllowed('Showing notifications isn\'t supported ☹️😢'); + return + } + if (Notification.permission === 'denied') { + showNotAllowed('You prevented us from showing notifications ☹️🤔'); + return + } + if (!'PushManager' in window) { + showNotAllowed("Push isn't allowed in your browser 🤔"); + return + } + subscribe(reg); +} + +const showNotAllowed = (message) => { + const button = document.querySelector('form>button'); + button.innerHTML = `${message}`; + button.setAttribute('disabled', 'true'); +}; + +function urlB64ToUint8Array(base64String) { + const padding = '='.repeat((4 - base64String.length % 4) % 4); + const base64 = (base64String + padding) + .replace(/\-/g, '+') + .replace(/_/g, '/'); + + const rawData = window.atob(base64); + const outputArray = new Uint8Array(rawData.length); + const outputData = outputArray.map((output, index) => rawData.charCodeAt(index)); + + return outputData; +} + +const subscribe = async (reg) => { + const subscription = await reg.pushManager.getSubscription(); + if (subscription) { + sendSubData(subscription); + return; + } + + const vapidMeta = document.querySelector('meta[name="vapid-key"]'); + const key = vapidMeta.content; + const options = { + userVisibleOnly: true, + // if key exists, create applicationServerKey property + ...(key && {applicationServerKey: urlB64ToUint8Array(key)}) + }; + + const sub = await reg.pushManager.subscribe(options); + sendSubData(sub) +}; + +const sendSubData = async (subscription) => { + const browser = navigator.userAgent.match(/(firefox|msie|chrome|safari|trident)/ig)[0].toLowerCase(); + const data = { + status_type: 'subscribe', + subscription: subscription.toJSON(), + browser: browser, + user_agent: browser, + }; + + const res = await fetch('/webpush/save_information', { + method: 'POST', + body: JSON.stringify(data), + headers: { + 'content-type': 'application/json', + + }, + credentials: "include" + }); + + handleResponse(res); +}; + +const handleResponse = (res) => { + console.log(res.status); +}; + +registerSw(); \ No newline at end of file diff --git a/templates/404.html b/templates/404.html new file mode 100644 index 0000000..a44afca --- /dev/null +++ b/templates/404.html @@ -0,0 +1,27 @@ +{% extends "tb_base.html" %} +{% load i18n %} +{% block content %} + +
+
+
+ 404 +
+ +
+ {% translate "Страница не найдена" %} +
+
+ + +
+ + {% translate "Вернуться на главную" %} + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/templates/blocks/b_finded_routes.html b/templates/blocks/b_finded_routes.html index dea6b3d..ce69d64 100644 --- a/templates/blocks/b_finded_routes.html +++ b/templates/blocks/b_finded_routes.html @@ -11,8 +11,43 @@
{% blocktranslate %} Упс... Ничего не найдено, попробуйте - изменить параметры поиска + изменить параметры поиска или создайте своё собственное объявление, чтобы все могли найти {% endblocktranslate %} + + {% if owner_type == "mover" %} + {% translate "Отправителя" %} + {% elif owner_type == "customer" %} + {% translate "Перевозчика" %} + {% endif %} + + + + + {% if user.is_authenticated %} + + {% translate "Создать объявление" %} + + + {% endif %} + + {% if not user.is_authenticated %} + + {% translate " Войти и Создать объявление" %} + + + + {% endif %} +
diff --git a/templates/blocks/profile/b_support_chat.html b/templates/blocks/profile/b_support_chat.html index c4558ef..894f425 100644 --- a/templates/blocks/profile/b_support_chat.html +++ b/templates/blocks/profile/b_support_chat.html @@ -13,7 +13,17 @@ {#

Техническая поддержка

#} {# #} {% if user.is_staff or staff %} -