add services/message-delivery-method-web-push/test-send-notification.js
Main daploy / deploy (push) Successful in 48s

This commit is contained in:
2024-11-24 11:51:45 +02:00
parent 89ec27ed23
commit 46c26e28e3
17 changed files with 272 additions and 90 deletions
-55
View File
@@ -1,55 +0,0 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var test_1 = require("@playwright/test");
// See here how to get started:
// https://playwright.dev/docs/intro
(0, test_1.test)('visits the app root url', function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
var page = _b.page;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, page.goto('/')];
case 1:
_c.sent();
return [4 /*yield*/, (0, test_1.expect)(page.locator('div.greetings > h1')).toHaveText('You did it!')];
case 2:
_c.sent();
return [2 /*return*/];
}
});
}); });
+2
View File
@@ -25,6 +25,7 @@
"pinia": "^2.2.6",
"pouchdb-browser": "^9.0.0",
"pouchdb-find": "^9.0.0",
"pouchdb-upsert": "^2.2.0",
"primeicons": "^7.0.0",
"primevue": "^4.2.1",
"qr-code-styling": "^1.8.4",
@@ -43,6 +44,7 @@
"@types/md5": "^2.3.5",
"@types/node": "^20.17.6",
"@types/pouchdb-browser": "^6.1.5",
"@types/pouchdb-upsert": "^2.2.9",
"@vitejs/plugin-vue": "^5.1.4",
"@vitest/eslint-plugin": "1.1.7",
"@vue/eslint-config-prettier": "^10.1.0",
+12 -1
View File
@@ -1,4 +1,15 @@
import PouchDB from 'pouchdb-browser'
import PouchDBFindPlugin from 'pouchdb-find'
import PouchDBUpsertPlugin from 'pouchdb-upsert'
export default PouchDB.plugin(PouchDBFindPlugin)
export default PouchDB.plugin(PouchDBFindPlugin).plugin(PouchDBUpsertPlugin)
// Type guard to check if the error is of type `Error` and has a `name` property
export function isNotFoundError(error: unknown): error is { name: string } {
return (
typeof error === 'object' &&
error !== null &&
'name' in error &&
(error as { name: string }).name === 'not_found'
)
}
+9 -1
View File
@@ -1,6 +1,10 @@
import PouchDB from '@/api/PouchDB'
import type { QRCodeDocument, MessageDocument } from '@/types/DBDocumentTypes'
import type {
QRCodeDocument,
MessageDocument,
WebPushSubscriptionDocument,
} from '@/types/DBDocumentTypes'
export const qrCodeDbRemote = new PouchDB<QRCodeDocument>('https://hereconnect.condev.ru/api/qr', {
skip_setup: true,
@@ -10,6 +14,10 @@ export const qrCodeDbLocal = new PouchDB<QRCodeDocument>('qr')
export const messagesDbLocal = new PouchDB<MessageDocument>('messages')
export const webPushSubscriptionsDbRemote = new PouchDB<WebPushSubscriptionDocument>(
'https://hereconnect.condev.ru/api/web_push_subscriptions',
)
export const messagesDbRemote = new PouchDB<MessageDocument>(
'https://hereconnect.condev.ru/api/messages',
{
+12 -5
View File
@@ -1,5 +1,8 @@
import type { QRCodeDocument } from '@/types/DBDocumentTypes'
import { qrCodeDbLocal, qrCodeDbRemote } from '@/api/dbs'
import { getUserUuid } from '@/utils/getUserUuid'
import { getBrowserUuid } from '@/utils/getBrowserUuid'
import { isNotFoundError } from '@/api/PouchDB'
const EPOHE = 1731661630981
@@ -21,6 +24,8 @@ export const createQrCodeDocument = async (
type: 'qr_code',
uri,
url: `https://hereconnect.condev.ru/read/${uri}`,
user_uuid: getUserUuid(),
browser_uuid: getBrowserUuid(),
created_at: new Date().toISOString(),
...qrCodeDocPartial,
}
@@ -48,11 +53,13 @@ export const createQrCodeDocument = async (
return qrCodeDoc
}
export const getQrCodeDocument = (uri: string) => {
return qrCodeDbLocal.get<QRCodeDocument>(`qr_code:${uri}`).catch((error) => {
if (error.name === 'not_found') {
return qrCodeDbRemote.get<QRCodeDocument>(`qr_code:${uri}`)
export const getQrCodeDocument = async (uri: string) => {
try {
return await qrCodeDbLocal.get<QRCodeDocument>(`qr_code:${uri}`)
} catch (error) {
if (isNotFoundError(error)) {
return await qrCodeDbRemote.get<QRCodeDocument>(`qr_code:${uri}`)
}
throw error
})
}
}
+41
View File
@@ -0,0 +1,41 @@
import type { WebPushSubscriptionDocument } from '@/types/DBDocumentTypes'
import { webPushSubscriptionsDbRemote } from '@/api/dbs'
import { getUserUuid } from '@/utils/getUserUuid'
import { getBrowserUuid } from '@/utils/getBrowserUuid'
export const saveWebPushSubscription = async (subscription: PushSubscription) => {
const type = 'web_push_subscription'
const user_uuid = getUserUuid()
const browser_uuid = getBrowserUuid()
const _id = `${type}:${user_uuid}:${browser_uuid}`
const created_at = new Date().toISOString()
const webPushSubscriptionDoc: WebPushSubscriptionDocument = {
_id,
type,
user_uuid,
browser_uuid,
subscription: subscription.toJSON(),
created_at,
}
try {
const { rev } = await webPushSubscriptionsDbRemote.upsert(
_id,
(doc): WebPushSubscriptionDocument | false => {
webPushSubscriptionDoc._rev = doc._rev
const isNotChanged =
JSON.stringify(webPushSubscriptionDoc.subscription) === JSON.stringify(doc.subscription)
if (isNotChanged) {
return false
}
webPushSubscriptionDoc.created_at = doc.created_at ?? created_at
webPushSubscriptionDoc.updated_at = doc.created_at ? new Date().toISOString() : created_at
return webPushSubscriptionDoc
},
)
webPushSubscriptionDoc._rev = rev
console.log('Подписка успешно сохранена', webPushSubscriptionDoc)
return webPushSubscriptionDoc
} catch (error) {
console.error('Ошибка сохранения подписки:', error)
}
}
@@ -13,6 +13,8 @@ import { type QRCodeDocument } from '@/types/DBDocumentTypes'
import { type DeliveryOption, DELIVERY_METHOD_WEB_PUSH } from '@/constants/deliveryOptions'
import { ref } from 'vue'
import { saveWebPushSubscription } from '@/api/webPush'
type DeliveryOptionWebPush = Extract<DeliveryOption, { method: typeof DELIVERY_METHOD_WEB_PUSH }>
defineProps<{
@@ -61,30 +63,7 @@ async function requestNotificationPermission(): Promise<boolean> {
'BMPwpR1Q24ZOFxy2T9M-I-Y6F6bucsHFVZKP8QYslgD_4hGCDv16qnZnji-ldngcZ_vBWVBwJ6OIfknVBnCxLsY',
})
console.log('Push-подписка создана:', subscription)
console.log(JSON.stringify(subscription))
// subscription = {
// endpoint:
// 'https://jmt17.google.com/fcm/send/eFYnP7qxt8A:APA91bHYGItzGpnzhXkfKzgMhAXgwcQXaLuRLqq9mt9RPS0VgGpEvVASxW8AF_fJmtSBtK-po0V3mM7fGWSN6tMCrImZqgZG14kGv0chQoghOLuWgHTUQYtQEqhd6f89eVonJdtjAlDN',
// expirationTime: null,
// keys: {
// p256dh:
// 'BAIGLAQ5cZg6e8psnK6vy_MJ1kUJbs2Tymjc38-_6zM1VQXWP2Yj-604uPMye4smHosNKmBEPRDJJOH6Wxr1MLQ',
// auth: '1k48wvT0U3pK_xaXW95Ekw',
// },
// }
// subscription = {
// endpoint:
// 'https://jmt17.google.com/fcm/send/eFYnP7qxt8A:APA91bHYGItzGpnzhXkfKzgMhAXgwcQXaLuRLqq9mt9RPS0VgGpEvVASxW8AF_fJmtSBtK-po0V3mM7fGWSN6tMCrImZqgZG14kGv0chQoghOLuWgHTUQYtQEqhd6f89eVonJdtjAlDN',
// expirationTime: null,
// keys: {
// p256dh:
// 'BAIGLAQ5cZg6e8psnK6vy_MJ1kUJbs2Tymjc38-_6zM1VQXWP2Yj-604uPMye4smHosNKmBEPRDJJOH6Wxr1MLQ',
// auth: '1k48wvT0U3pK_xaXW95Ekw',
// },
// }
// Здесь вы можете сохранить подписку на сервере
await saveWebPushSubscription(subscription)
return true
} catch (err) {
console.error('Ошибка при создании Push-подписки:', err)
@@ -0,0 +1,2 @@
export const LOCALSTORAGE_KEY_USER_UUID = 'user_uuid'
export const LOCALSTORAGE_KEY_BROWSER_UUID = 'browser_uuid'
@@ -21,7 +21,10 @@ export interface QRCodeDocument extends BaseDocument {
url: string
/** Идентификатор пользователя, который создал QR‑код */
// user_uuid: string
user_uuid: string
/** Идентификатор браузера, через который был создан QR-код */
browser_uuid: string
/** Название объекта, для которого создан QR‑код, например "Мой автомобиль" */
name: string
@@ -0,0 +1,11 @@
import type { BaseDocument } from '@/types/DBDocumentTypes/BaseDocument'
export interface WebPushSubscriptionDocument extends BaseDocument {
_id: string // Формат: "web_push_subscription:<user_uuid>:<browser_uuid>"
type: 'web_push_subscription'
user_uuid: string // UUID пользователя, связанного с подпиской
browser_uuid: string // UUID браузера, связанного с подпиской
subscription: PushSubscriptionJSON
created_at: string // Дата создания подписки в ISO формате
updated_at?: string // Дата последнего обновления подписки
}
@@ -2,3 +2,4 @@ export * from './BaseDocument'
export * from './QRCodeDocument'
export * from './MessageDocument'
export * from './UserDocument'
export * from './WebPushSubscriptionDocument'
+10
View File
@@ -0,0 +1,10 @@
import { LOCALSTORAGE_KEY_BROWSER_UUID } from '@/constants/localStorageKeys'
export function getBrowserUuid(): string {
let browserUuid = localStorage.getItem(LOCALSTORAGE_KEY_BROWSER_UUID)
if (!browserUuid) {
browserUuid = crypto.randomUUID() // Браузерная API для генерации UUID
localStorage.setItem(LOCALSTORAGE_KEY_BROWSER_UUID, browserUuid)
}
return browserUuid
}
+10
View File
@@ -0,0 +1,10 @@
import { LOCALSTORAGE_KEY_USER_UUID } from '@/constants/localStorageKeys'
export function getUserUuid(): string {
let userUuid = localStorage.getItem(LOCALSTORAGE_KEY_USER_UUID)
if (!userUuid) {
userUuid = crypto.randomUUID()
localStorage.setItem(LOCALSTORAGE_KEY_USER_UUID, userUuid)
}
return userUuid
}