diff --git a/client/src/app/+my-library/my-history/my-history.component.html b/client/src/app/+my-library/my-history/my-history.component.html index 8e564cf93..14bf01804 100644 --- a/client/src/app/+my-library/my-history/my-history.component.html +++ b/client/src/app/+my-library/my-history/my-history.component.html @@ -13,9 +13,9 @@ - @@ -30,4 +30,10 @@ [enableSelection]="false" [disabled]="disabled" #videosSelection -> +> + +
+ +
+
+ diff --git a/client/src/app/+my-library/my-history/my-history.component.scss b/client/src/app/+my-library/my-history/my-history.component.scss index cb8507569..3257b2215 100644 --- a/client/src/app/+my-library/my-history/my-history.component.scss +++ b/client/src/app/+my-library/my-history/my-history.component.scss @@ -53,6 +53,11 @@ @include row-blocks($column-responsive: false); } +.action-button { + display: flex; + align-self: flex-end; +} + @media screen and (max-width: $small-view) { .top-buttons { grid-template-columns: auto 1fr auto; diff --git a/client/src/app/+my-library/my-history/my-history.component.ts b/client/src/app/+my-library/my-history/my-history.component.ts index 95cfaee41..34efe5558 100644 --- a/client/src/app/+my-library/my-history/my-history.component.ts +++ b/client/src/app/+my-library/my-history/my-history.component.ts @@ -123,14 +123,25 @@ export class MyHistoryComponent implements OnInit, DisableForReuseHook { }) } - async deleteHistory () { + deleteHistoryElement (video: Video) { + this.userHistoryService.deleteUserVideoHistoryElement(video) + .subscribe({ + next: () => { + this.videos = this.videos.filter(v => v.id !== video.id) + }, + + error: err => this.notifier.error(err.message) + }) + } + + async clearAllHistory () { const title = $localize`Delete videos history` const message = $localize`Are you sure you want to delete all your videos history?` const res = await this.confirmService.confirm(message, title) if (res !== true) return - this.userHistoryService.deleteUserVideosHistory() + this.userHistoryService.clearAllUserVideosHistory() .subscribe({ next: () => { this.notifier.success($localize`Videos history deleted`) diff --git a/client/src/app/shared/shared-main/users/user-history.service.ts b/client/src/app/shared/shared-main/users/user-history.service.ts index a4841897d..e28bcdca9 100644 --- a/client/src/app/shared/shared-main/users/user-history.service.ts +++ b/client/src/app/shared/shared-main/users/user-history.service.ts @@ -34,7 +34,13 @@ export class UserHistoryService { ) } - deleteUserVideosHistory () { + deleteUserVideoHistoryElement (video: Video) { + return this.authHttp + .delete(UserHistoryService.BASE_USER_VIDEOS_HISTORY_URL + '/' + video.id) + .pipe(catchError(err => this.restExtractor.handleError(err))) + } + + clearAllUserVideosHistory () { return this.authHttp .post(UserHistoryService.BASE_USER_VIDEOS_HISTORY_URL + '/remove', {}) .pipe( diff --git a/server/controllers/api/users/my-history.ts b/server/controllers/api/users/my-history.ts index 2fcb25acf..bc5b40f59 100644 --- a/server/controllers/api/users/my-history.ts +++ b/server/controllers/api/users/my-history.ts @@ -9,7 +9,8 @@ import { paginationValidator, setDefaultPagination, userHistoryListValidator, - userHistoryRemoveValidator + userHistoryRemoveAllValidator, + userHistoryRemoveElementValidator } from '../../../middlewares' import { UserVideoHistoryModel } from '../../../models/user/user-video-history' @@ -23,10 +24,16 @@ myVideosHistoryRouter.get('/me/history/videos', asyncMiddleware(listMyVideosHistory) ) +myVideosHistoryRouter.delete('/me/history/videos/:videoId', + authenticate, + userHistoryRemoveElementValidator, + asyncMiddleware(removeUserHistoryElement) +) + myVideosHistoryRouter.post('/me/history/videos/remove', authenticate, - userHistoryRemoveValidator, - asyncRetryTransactionMiddleware(removeUserHistory) + userHistoryRemoveAllValidator, + asyncRetryTransactionMiddleware(removeAllUserHistory) ) // --------------------------------------------------------------------------- @@ -45,7 +52,15 @@ async function listMyVideosHistory (req: express.Request, res: express.Response) return res.json(getFormattedObjects(resultList.data, resultList.total)) } -async function removeUserHistory (req: express.Request, res: express.Response) { +async function removeUserHistoryElement (req: express.Request, res: express.Response) { + const user = res.locals.oauth.token.User + + await UserVideoHistoryModel.removeUserHistoryElement(user, parseInt(req.params.videoId + '')) + + return res.sendStatus(HttpStatusCode.NO_CONTENT_204) +} + +async function removeAllUserHistory (req: express.Request, res: express.Response) { const user = res.locals.oauth.token.User const beforeDate = req.body.beforeDate || null diff --git a/server/middlewares/validators/user-history.ts b/server/middlewares/validators/user-history.ts index f9be26627..541910be5 100644 --- a/server/middlewares/validators/user-history.ts +++ b/server/middlewares/validators/user-history.ts @@ -1,6 +1,6 @@ import express from 'express' -import { body, query } from 'express-validator' -import { exists, isDateValid } from '../../helpers/custom-validators/misc' +import { body, param, query } from 'express-validator' +import { exists, isDateValid, isIdValid } from '../../helpers/custom-validators/misc' import { logger } from '../../helpers/logger' import { areValidationErrors } from './shared' @@ -18,13 +18,26 @@ const userHistoryListValidator = [ } ] -const userHistoryRemoveValidator = [ +const userHistoryRemoveAllValidator = [ body('beforeDate') .optional() .custom(isDateValid).withMessage('Should have a before date that conforms to ISO 8601'), (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking userHistoryRemoveValidator parameters', { parameters: req.body }) + logger.debug('Checking userHistoryRemoveAllValidator parameters', { parameters: req.body }) + + if (areValidationErrors(req, res)) return + + return next() + } +] + +const userHistoryRemoveElementValidator = [ + param('videoId') + .custom(isIdValid).withMessage('Should have a valid video id'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking userHistoryRemoveElementValidator parameters', { parameters: req.params }) if (areValidationErrors(req, res)) return @@ -36,5 +49,6 @@ const userHistoryRemoveValidator = [ export { userHistoryListValidator, - userHistoryRemoveValidator + userHistoryRemoveElementValidator, + userHistoryRemoveAllValidator } diff --git a/server/models/user/user-video-history.ts b/server/models/user/user-video-history.ts index 92f4fe7a1..f4d0889a1 100644 --- a/server/models/user/user-video-history.ts +++ b/server/models/user/user-video-history.ts @@ -69,6 +69,17 @@ export class UserVideoHistoryModel extends Model