mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-03-16 17:50:57 +03:00
Added notifications - (WIP, boilerplate)
This commit is contained in:
@@ -2755,6 +2755,36 @@ components:
|
||||
type: string
|
||||
date:
|
||||
type: string
|
||||
Notification:
|
||||
required:
|
||||
- uid
|
||||
- type
|
||||
- text
|
||||
- read
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
text:
|
||||
type: string
|
||||
uid:
|
||||
type: string
|
||||
action:
|
||||
$ref: '#/components/schemas/NotificationAction'
|
||||
read:
|
||||
type: boolean
|
||||
data:
|
||||
type: object
|
||||
NotificationAction:
|
||||
required:
|
||||
- type
|
||||
- icon
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
icon:
|
||||
type: string
|
||||
BaseChangePermissionsRequest:
|
||||
required:
|
||||
- permission
|
||||
@@ -2886,6 +2916,29 @@ components:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/UserPermission'
|
||||
DeleteNotificationRequest:
|
||||
required:
|
||||
- uid
|
||||
type: object
|
||||
properties:
|
||||
uid:
|
||||
type: string
|
||||
SetNotificationsToReadRequest:
|
||||
required:
|
||||
- uids
|
||||
type: object
|
||||
properties:
|
||||
uids:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
GetNotificationsResponse:
|
||||
type: object
|
||||
properties:
|
||||
notifications:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Notification'
|
||||
securitySchemes:
|
||||
Auth query parameter:
|
||||
name: apiKey
|
||||
|
||||
@@ -1992,6 +1992,44 @@ app.post('/api/changeRolePermissions', optionalJwt, async (req, res) => {
|
||||
res.send({success: success});
|
||||
});
|
||||
|
||||
// notifications
|
||||
|
||||
app.post('/api/getNotifications', optionalJwt, async (req, res) => {
|
||||
const uuid = req.user.uid;
|
||||
|
||||
const notifications = await db_api.getRecords('notifications', {user_uid: uuid});
|
||||
|
||||
res.send({notifications: notifications});
|
||||
});
|
||||
|
||||
// set notifications to read
|
||||
app.post('/api/setNotificationsToRead', optionalJwt, async (req, res) => {
|
||||
const uids = req.body.uids;
|
||||
|
||||
// TODO: do a bulk update
|
||||
const success = true; // await db_api.updateRecords('notifications', {user_uid: uuid});
|
||||
|
||||
res.send({success: success});
|
||||
});
|
||||
|
||||
app.post('/api/deleteNotification', optionalJwt, async (req, res) => {
|
||||
const uid = req.body.uid;
|
||||
|
||||
const success = await db_api.removeRecord('notifications', {uid: uid});
|
||||
|
||||
res.send({success: success});
|
||||
});
|
||||
|
||||
app.post('/api/deleteAllNotifications', optionalJwt, async (req, res) => {
|
||||
const uuid = req.user.uid;
|
||||
|
||||
const success = await db_api.removeAllRecords('notifications', {user_uid: uuid});
|
||||
|
||||
res.send({success: success});
|
||||
});
|
||||
|
||||
// web server
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
//if the request is not html then move along
|
||||
var accept = req.accepts('html', 'json', 'xml');
|
||||
|
||||
@@ -58,6 +58,10 @@ const tables = {
|
||||
name: 'tasks',
|
||||
primary_key: 'key'
|
||||
},
|
||||
notifications: {
|
||||
name: 'notifications',
|
||||
primary_key: 'uid'
|
||||
},
|
||||
test: {
|
||||
name: 'test'
|
||||
}
|
||||
|
||||
13
backend/notifications.js
Normal file
13
backend/notifications.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const utils = require('./utils');
|
||||
const logger = require('./logger');
|
||||
const db_api = require('./db');
|
||||
|
||||
exports.sendNotification = async () => {
|
||||
// TODO: hook into third party service
|
||||
|
||||
const notification = {}
|
||||
|
||||
await db_api.insertRecordIntoTable('notifications', notification);
|
||||
|
||||
return notification;
|
||||
}
|
||||
@@ -28,6 +28,7 @@ export type { DBInfoResponse } from './models/DBInfoResponse';
|
||||
export type { DeleteAllFilesResponse } from './models/DeleteAllFilesResponse';
|
||||
export type { DeleteCategoryRequest } from './models/DeleteCategoryRequest';
|
||||
export type { DeleteMp3Mp4Request } from './models/DeleteMp3Mp4Request';
|
||||
export type { DeleteNotificationRequest } from './models/DeleteNotificationRequest';
|
||||
export type { DeletePlaylistRequest } from './models/DeletePlaylistRequest';
|
||||
export type { DeleteSubscriptionFileRequest } from './models/DeleteSubscriptionFileRequest';
|
||||
export type { DeleteUserRequest } from './models/DeleteUserRequest';
|
||||
@@ -63,6 +64,7 @@ export type { GetLogsRequest } from './models/GetLogsRequest';
|
||||
export type { GetLogsResponse } from './models/GetLogsResponse';
|
||||
export type { GetMp3sResponse } from './models/GetMp3sResponse';
|
||||
export type { GetMp4sResponse } from './models/GetMp4sResponse';
|
||||
export type { GetNotificationsResponse } from './models/GetNotificationsResponse';
|
||||
export type { GetPlaylistRequest } from './models/GetPlaylistRequest';
|
||||
export type { GetPlaylistResponse } from './models/GetPlaylistResponse';
|
||||
export type { GetPlaylistsRequest } from './models/GetPlaylistsRequest';
|
||||
@@ -77,12 +79,15 @@ export type { IncrementViewCountRequest } from './models/IncrementViewCountReque
|
||||
export type { inline_response_200_15 } from './models/inline_response_200_15';
|
||||
export type { LoginRequest } from './models/LoginRequest';
|
||||
export type { LoginResponse } from './models/LoginResponse';
|
||||
export type { Notification } from './models/Notification';
|
||||
export type { NotificationAction } from './models/NotificationAction';
|
||||
export type { Playlist } from './models/Playlist';
|
||||
export type { RegisterRequest } from './models/RegisterRequest';
|
||||
export type { RegisterResponse } from './models/RegisterResponse';
|
||||
export type { RestoreDBBackupRequest } from './models/RestoreDBBackupRequest';
|
||||
export { Schedule } from './models/Schedule';
|
||||
export type { SetConfigRequest } from './models/SetConfigRequest';
|
||||
export type { SetNotificationsToReadRequest } from './models/SetNotificationsToReadRequest';
|
||||
export type { SharingToggle } from './models/SharingToggle';
|
||||
export type { Sort } from './models/Sort';
|
||||
export type { SubscribeRequest } from './models/SubscribeRequest';
|
||||
|
||||
7
src/api-types/models/DeleteNotificationRequest.ts
Normal file
7
src/api-types/models/DeleteNotificationRequest.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type DeleteNotificationRequest = {
|
||||
uid: string;
|
||||
};
|
||||
9
src/api-types/models/GetNotificationsResponse.ts
Normal file
9
src/api-types/models/GetNotificationsResponse.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { Notification } from './Notification';
|
||||
|
||||
export type GetNotificationsResponse = {
|
||||
notifications?: Array<Notification>;
|
||||
};
|
||||
14
src/api-types/models/Notification.ts
Normal file
14
src/api-types/models/Notification.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { NotificationAction } from './NotificationAction';
|
||||
|
||||
export type Notification = {
|
||||
type: string;
|
||||
text: string;
|
||||
uid: string;
|
||||
action?: NotificationAction;
|
||||
read: boolean;
|
||||
data?: any;
|
||||
};
|
||||
8
src/api-types/models/NotificationAction.ts
Normal file
8
src/api-types/models/NotificationAction.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type NotificationAction = {
|
||||
type: string;
|
||||
icon: string;
|
||||
};
|
||||
7
src/api-types/models/SetNotificationsToReadRequest.ts
Normal file
7
src/api-types/models/SetNotificationsToReadRequest.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type SetNotificationsToReadRequest = {
|
||||
uids: Array<string>;
|
||||
};
|
||||
@@ -87,6 +87,7 @@ import { SkipAdButtonComponent } from './components/skip-ad-button/skip-ad-butto
|
||||
import { TasksComponent } from './components/tasks/tasks.component';
|
||||
import { UpdateTaskScheduleDialogComponent } from './dialogs/update-task-schedule-dialog/update-task-schedule-dialog.component';
|
||||
import { RestoreDbDialogComponent } from './dialogs/restore-db-dialog/restore-db-dialog.component';
|
||||
import { NotificationsComponent } from './components/notifications/notifications.component';
|
||||
|
||||
registerLocaleData(es, 'es');
|
||||
|
||||
@@ -132,7 +133,8 @@ registerLocaleData(es, 'es');
|
||||
SkipAdButtonComponent,
|
||||
TasksComponent,
|
||||
UpdateTaskScheduleDialogComponent,
|
||||
RestoreDbDialogComponent
|
||||
RestoreDbDialogComponent,
|
||||
NotificationsComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
.notification-divider {
|
||||
margin-bottom: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.notification-title {
|
||||
margin-bottom: 6px;
|
||||
text-align: center
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<h4 *ngIf="notifications !== null && notifications.length === 0 && read_notifications.length === 0" style="text-align: center; margin: 10px;">No notifications available</h4>
|
||||
<div style="margin: 10px;" *ngIf="notifications?.length > 0">
|
||||
<h4 class="notification-title">New notifications</h4>
|
||||
<div *ngFor="let notification of appService.notifications; let i = index;">
|
||||
<mat-divider class="notification-divider"></mat-divider>
|
||||
<div style="display: inline-block;">
|
||||
<button (click)="deleteNotification(notification.id, i, false)" mat-icon-button><mat-icon>close</mat-icon></button>
|
||||
</div>
|
||||
<div style="display: inline-block">
|
||||
{{notification.title}}
|
||||
</div>
|
||||
<div style="margin-left: 10px; float: right;" *ngIf="notification.action">
|
||||
<button (click)="notificationAction(notification)" [color]="notification.action.warn ? 'warn' : 'primary'" mat-raised-button>{{notification.action.title}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin: 10px;" *ngIf="read_notifications?.length > 0">
|
||||
<h4 class="notification-title">Old notifications</h4>
|
||||
<div *ngFor="let notification of appService.read_notifications; let i = index">
|
||||
<mat-divider class="notification-divider"></mat-divider>
|
||||
<div style="display: inline-block;">
|
||||
<button (click)="deleteNotification(notification.id, i, true)" mat-icon-button><mat-icon>close</mat-icon></button>
|
||||
</div>
|
||||
<div style="display: inline-block">
|
||||
{{notification.title}}
|
||||
</div>
|
||||
<div style="margin-left: 10px; float: right" *ngIf="notification.action">
|
||||
<button (click)="notificationAction(notification)" [color]="notification.action.warn ? 'warn' : 'primary'" mat-raised-button>{{notification.action.title}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NotificationsComponent } from './notifications.component';
|
||||
|
||||
describe('NotificationsComponent', () => {
|
||||
let component: NotificationsComponent;
|
||||
let fixture: ComponentFixture<NotificationsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ NotificationsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(NotificationsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
76
src/app/components/notifications/notifications.component.ts
Normal file
76
src/app/components/notifications/notifications.component.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Component, ElementRef, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { MatMenu, MatMenuTrigger } from '@angular/material/menu';
|
||||
import { Router } from '@angular/router';
|
||||
import { PostsService } from 'app/posts.services';
|
||||
import { Notification } from 'api-types';
|
||||
|
||||
// TODO: fill this out
|
||||
const NOTIFICATION_ACTION_TO_STRING = {}
|
||||
|
||||
@Component({
|
||||
selector: 'app-notifications',
|
||||
templateUrl: './notifications.component.html',
|
||||
styleUrls: ['./notifications.component.css']
|
||||
})
|
||||
export class NotificationsComponent implements OnInit {
|
||||
|
||||
notifications = null;
|
||||
read_notifications = null;
|
||||
|
||||
@Input() menu: MatMenuTrigger;
|
||||
@Output() notificationCount = new EventEmitter<number>();
|
||||
|
||||
constructor(public postsService: PostsService, private router: Router, private elRef: ElementRef) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
// wait for init
|
||||
if (this.postsService.initialized) {
|
||||
this.getNotifications();
|
||||
} else {
|
||||
this.postsService.service_initialized.subscribe(init => {
|
||||
if (init) {
|
||||
this.getNotifications();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getNotifications(): void {
|
||||
this.postsService.getNotifications().subscribe(res => {
|
||||
this.notifications = res['notifications'].filter(notification => notification.read == false);
|
||||
this.read_notifications = res['notifications'].filter(notification => notification.read == true);
|
||||
this.notificationCount.emit(this.notifications.length);
|
||||
});
|
||||
}
|
||||
|
||||
notificationAction(notification: Notification): void {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
deleteNotification(uid: string, index: number): void {
|
||||
this.postsService.deleteNotification(uid).subscribe(res => {
|
||||
console.log(res);
|
||||
// TODO: remove from array
|
||||
this.notificationCount.emit(this.notifications.length);
|
||||
});
|
||||
}
|
||||
|
||||
deleteAllNotifications(): void {
|
||||
this.postsService.deleteAllNotifications().subscribe(res => {
|
||||
console.log(res);
|
||||
this.notifications = [];
|
||||
this.read_notifications = [];
|
||||
this.getNotifications();
|
||||
});
|
||||
this.notificationCount.emit(0);
|
||||
}
|
||||
|
||||
setNotificationsToRead(): void {
|
||||
const uids = this.notifications.map(notification => notification.uid);
|
||||
this.postsService.setNotificationsToRead(uids).subscribe(res => {
|
||||
console.log(res);
|
||||
});
|
||||
this.notificationCount.emit(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import 'rxjs/add/observable/throw';
|
||||
import { THEMES_CONFIG } from '../themes';
|
||||
import { Router, CanActivate, ActivatedRouteSnapshot } from '@angular/router';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import * as Fingerprint2 from 'fingerprintjs2';
|
||||
import {
|
||||
@@ -101,7 +101,10 @@ import {
|
||||
Sort,
|
||||
FileTypeFilter,
|
||||
GetAllFilesRequest,
|
||||
GetAllTasksResponse
|
||||
GetAllTasksResponse,
|
||||
DeleteNotificationRequest,
|
||||
SetNotificationsToReadRequest,
|
||||
GetNotificationsResponse
|
||||
} from '../api-types';
|
||||
import { isoLangs } from './settings/locales_list';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
@@ -833,7 +836,31 @@ export class PostsService implements CanActivate {
|
||||
return this.http.get(sponsor_block_api_path + `skipSegments/${id_hash}`);
|
||||
}
|
||||
|
||||
public openSnackBar(message: string, action: string = '') {
|
||||
// notifications
|
||||
|
||||
getNotifications(): Observable<GetNotificationsResponse> {
|
||||
return this.http.post<GetNotificationsResponse>(this.path + 'getNotifications', {},
|
||||
this.httpOptions);
|
||||
}
|
||||
|
||||
setNotificationsToRead(uids: string[]): Observable<SuccessObject> {
|
||||
const body: SetNotificationsToReadRequest = {uids: uids};
|
||||
return this.http.post<SuccessObject>(this.path + 'setNotificationsToRead', body,
|
||||
this.httpOptions);
|
||||
}
|
||||
|
||||
deleteNotification(uid: string): Observable<SuccessObject> {
|
||||
const body: DeleteNotificationRequest = {uid: uid};
|
||||
return this.http.post<SuccessObject>(this.path + 'deleteNotification', body,
|
||||
this.httpOptions);
|
||||
}
|
||||
|
||||
deleteAllNotifications(): Observable<SuccessObject> {
|
||||
return this.http.post<SuccessObject>(this.path + 'deleteNotifications', {},
|
||||
this.httpOptions);
|
||||
}
|
||||
|
||||
public openSnackBar(message: string, action = ''): void {
|
||||
this.snackBar.open(message, action, {
|
||||
duration: 2000,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user