mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2024-11-22 08:46:54 -06:00
Add avatar in comments
This commit is contained in:
parent
265ba139eb
commit
cf117aaafc
@ -1,6 +1,8 @@
|
||||
<menu>
|
||||
<div *ngIf="isLoggedIn" class="logged-in-block">
|
||||
<img [src]="getUserAvatarUrl()" alt="Avatar" />
|
||||
<a routerLink="/account/settings">
|
||||
<img [src]="getUserAvatarUrl()" alt="Avatar" />
|
||||
</a>
|
||||
|
||||
<div class="logged-in-info">
|
||||
<a routerLink="/account/settings" class="logged-in-username">{{ user.username }}</a>
|
||||
|
@ -1,9 +1,13 @@
|
||||
<form novalidate [formGroup]="form" (ngSubmit)="formValidated()">
|
||||
<div class="form-group">
|
||||
<textarea placeholder="Add comment..." formControlName="text" [ngClass]="{ 'input-error': formErrors['text'] }" #textarea>
|
||||
</textarea>
|
||||
<div *ngIf="formErrors.text" class="form-error">
|
||||
{{ formErrors.text }}
|
||||
<div class="avatar-and-textarea">
|
||||
<img [src]="getUserAvatarUrl()" alt="Avatar" />
|
||||
|
||||
<div class="form-group">
|
||||
<textarea placeholder="Add comment..." formControlName="text" [ngClass]="{ 'input-error': formErrors['text'] }" #textarea>
|
||||
</textarea>
|
||||
<div *ngIf="formErrors.text" class="form-error">
|
||||
{{ formErrors.text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,12 +1,25 @@
|
||||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
.form-group {
|
||||
.avatar-and-textarea {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
@include peertube-textarea(100%, 150px);
|
||||
img {
|
||||
@include avatar(36px);
|
||||
|
||||
vertical-align: top;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
flex-grow: 1;
|
||||
margin: 0;
|
||||
|
||||
textarea {
|
||||
@include peertube-textarea(100%, 60px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.submit-comment {
|
||||
|
@ -5,6 +5,7 @@ import { Observable } from 'rxjs/Observable'
|
||||
import { VideoCommentCreate } from '../../../../../../shared/models/videos/video-comment.model'
|
||||
import { FormReactive } from '../../../shared'
|
||||
import { VIDEO_COMMENT_TEXT } from '../../../shared/forms/form-validators/video-comment'
|
||||
import { User } from '../../../shared/users'
|
||||
import { Video } from '../../../shared/video/video.model'
|
||||
import { VideoComment } from './video-comment.model'
|
||||
import { VideoCommentService } from './video-comment.service'
|
||||
@ -15,6 +16,7 @@ import { VideoCommentService } from './video-comment.service'
|
||||
styleUrls: ['./video-comment-add.component.scss']
|
||||
})
|
||||
export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
||||
@Input() user: User
|
||||
@Input() video: Video
|
||||
@Input() parentComment: VideoComment
|
||||
@Input() focusOnInit = false
|
||||
@ -79,6 +81,10 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
||||
return this.form.value['text']
|
||||
}
|
||||
|
||||
getUserAvatarUrl () {
|
||||
return this.user.getAvatarUrl()
|
||||
}
|
||||
|
||||
private addCommentReply (commentCreate: VideoCommentCreate) {
|
||||
return this.videoCommentService
|
||||
.addCommentReply(this.video.id, this.parentComment.id, commentCreate)
|
||||
|
@ -1,29 +1,37 @@
|
||||
<div class="comment">
|
||||
<div class="comment-account-date">
|
||||
<div class="comment-account">{{ comment.by }}</div>
|
||||
<div class="comment-date">{{ comment.createdAt | myFromNow }}</div>
|
||||
</div>
|
||||
<div>{{ comment.text }}</div>
|
||||
<div class="root-comment">
|
||||
<img [src]="getAvatarUrl(comment.account)" alt="Avatar" />
|
||||
|
||||
<div class="comment-actions">
|
||||
<div *ngIf="isUserLoggedIn()" (click)="onWantToReply()" class="comment-action-reply">Reply</div>
|
||||
</div>
|
||||
<div class="comment">
|
||||
<div class="comment-account-date">
|
||||
<div class="comment-account">{{ comment.by }}</div>
|
||||
<div class="comment-date">{{ comment.createdAt | myFromNow }}</div>
|
||||
</div>
|
||||
<div>{{ comment.text }}</div>
|
||||
|
||||
<my-video-comment-add
|
||||
*ngIf="isUserLoggedIn() && inReplyToCommentId === comment.id" [video]="video" [parentComment]="comment" [focusOnInit]="true"
|
||||
(commentCreated)="onCommentReplyCreated($event)"
|
||||
></my-video-comment-add>
|
||||
<div class="comment-actions">
|
||||
<div *ngIf="isUserLoggedIn()" (click)="onWantToReply()" class="comment-action-reply">Reply</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="commentTree" class="children">
|
||||
<div *ngFor="let commentChild of commentTree.children">
|
||||
<my-video-comment
|
||||
[comment]="commentChild.comment"
|
||||
[video]="video"
|
||||
[inReplyToCommentId]="inReplyToCommentId"
|
||||
[commentTree]="commentChild"
|
||||
(wantedToReply)="onWantedToReply($event)"
|
||||
(resetReply)="onResetReply()"
|
||||
></my-video-comment>
|
||||
<my-video-comment-add
|
||||
*ngIf="isUserLoggedIn() && inReplyToCommentId === comment.id"
|
||||
[user]="user"
|
||||
[video]="video"
|
||||
[parentComment]="comment"
|
||||
[focusOnInit]="true"
|
||||
(commentCreated)="onCommentReplyCreated($event)"
|
||||
></my-video-comment-add>
|
||||
|
||||
<div *ngIf="commentTree" class="children">
|
||||
<div *ngFor="let commentChild of commentTree.children">
|
||||
<my-video-comment
|
||||
[comment]="commentChild.comment"
|
||||
[video]="video"
|
||||
[inReplyToCommentId]="inReplyToCommentId"
|
||||
[commentTree]="commentChild"
|
||||
(wantedToReply)="onWantedToReply($event)"
|
||||
(resetReply)="onResetReply()"
|
||||
></my-video-comment>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,38 +1,41 @@
|
||||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
.comment {
|
||||
.root-comment {
|
||||
font-size: 15px;
|
||||
margin-top: 30px;
|
||||
display: flex;
|
||||
|
||||
.comment-account-date {
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
img {
|
||||
@include avatar(36px);
|
||||
|
||||
.comment-account {
|
||||
font-weight: $font-bold;
|
||||
}
|
||||
|
||||
.comment-date {
|
||||
color: #585858;
|
||||
margin-left: 10px;
|
||||
}
|
||||
margin-top: 5px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.comment-actions {
|
||||
margin: 10px 0;
|
||||
|
||||
.comment-action-reply {
|
||||
color: #585858;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.children {
|
||||
margin-left: 20px;
|
||||
|
||||
.comment {
|
||||
margin-top: 15px;
|
||||
flex-grow: 1;
|
||||
|
||||
.comment-account-date {
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
|
||||
.comment-account {
|
||||
font-weight: $font-bold;
|
||||
}
|
||||
|
||||
.comment-date {
|
||||
color: #585858;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-actions {
|
||||
margin: 10px 0;
|
||||
|
||||
.comment-action-reply {
|
||||
color: #585858;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core'
|
||||
import { Account as AccountInterface } from '../../../../../../shared/models/actors'
|
||||
import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model'
|
||||
import { AuthService } from '../../../core/auth'
|
||||
import { Account } from '../../../shared/account/account.model'
|
||||
import { Video } from '../../../shared/video/video.model'
|
||||
import { VideoComment } from './video-comment.model'
|
||||
|
||||
@ -18,7 +20,10 @@ export class VideoCommentComponent {
|
||||
@Output() wantedToReply = new EventEmitter<VideoComment>()
|
||||
@Output() resetReply = new EventEmitter()
|
||||
|
||||
constructor (private authService: AuthService) {
|
||||
constructor (private authService: AuthService) {}
|
||||
|
||||
get user () {
|
||||
return this.authService.getUser()
|
||||
}
|
||||
|
||||
onCommentReplyCreated (createdComment: VideoComment) {
|
||||
@ -52,4 +57,8 @@ export class VideoCommentComponent {
|
||||
onResetReply () {
|
||||
this.resetReply.emit()
|
||||
}
|
||||
|
||||
getAvatarUrl (account: AccountInterface) {
|
||||
return Account.GET_ACCOUNT_AVATAR_URL(account)
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Account } from '../../../../../../shared/models/actors'
|
||||
import { VideoComment as VideoCommentServerModel } from '../../../../../../shared/models/videos/video-comment.model'
|
||||
|
||||
export class VideoComment implements VideoCommentServerModel {
|
||||
@ -9,10 +10,7 @@ export class VideoComment implements VideoCommentServerModel {
|
||||
videoId: number
|
||||
createdAt: Date | string
|
||||
updatedAt: Date | string
|
||||
account: {
|
||||
name: string
|
||||
host: string
|
||||
}
|
||||
account: Account
|
||||
totalReplies: number
|
||||
|
||||
by: string
|
||||
|
@ -7,6 +7,7 @@
|
||||
<my-video-comment-add
|
||||
*ngIf="isUserLoggedIn()"
|
||||
[video]="video"
|
||||
[user]="user"
|
||||
(commentCreated)="onCommentThreadCreated($event)"
|
||||
></my-video-comment-add>
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
font-weight: $font-semibold;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
margin-left: 56px;
|
||||
}
|
||||
|
||||
.glyphicon, .comment-thread-loading {
|
||||
|
@ -6,7 +6,6 @@ import { ComponentPagination } from '../../../shared/rest/component-pagination.m
|
||||
import { User } from '../../../shared/users'
|
||||
import { SortField } from '../../../shared/video/sort-field.type'
|
||||
import { VideoDetails } from '../../../shared/video/video-details.model'
|
||||
import { Video } from '../../../shared/video/video.model'
|
||||
import { VideoComment } from './video-comment.model'
|
||||
import { VideoCommentService } from './video-comment.service'
|
||||
|
||||
|
@ -14,14 +14,16 @@
|
||||
|
||||
<div class="video-info-actions">
|
||||
<div
|
||||
*ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'like' }" (click)="setLike()"
|
||||
class="action-button action-button-like">
|
||||
*ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'like' }" (click)="setLike()"
|
||||
class="action-button action-button-like"
|
||||
>
|
||||
<span class="icon icon-like" title="Like this video" ></span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'dislike' }" (click)="setDislike()"
|
||||
class="action-button action-button-dislike">
|
||||
*ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'dislike' }" (click)="setDislike()"
|
||||
class="action-button action-button-dislike"
|
||||
>
|
||||
<span class="icon icon-dislike" title="Dislike this video"></span>
|
||||
</div>
|
||||
|
||||
|
@ -176,9 +176,9 @@
|
||||
font-size: 13px;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 3px;
|
||||
@include avatar(18px);
|
||||
|
||||
margin-left: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
import * as validator from 'validator'
|
||||
import { CONSTRAINTS_FIELDS } from '../../../initializers'
|
||||
import { isAccountNameValid } from '../accounts'
|
||||
import { exists } from '../misc'
|
||||
import { isVideoChannelNameValid } from '../video-channels'
|
||||
import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc'
|
||||
|
||||
function isActorEndpointsObjectValid (endpointObject: any) {
|
||||
@ -32,10 +30,6 @@ function isActorPreferredUsernameValid (preferredUsername: string) {
|
||||
return exists(preferredUsername) && validator.matches(preferredUsername, actorNameRegExp)
|
||||
}
|
||||
|
||||
function isActorNameValid (name: string) {
|
||||
return isAccountNameValid(name) || isVideoChannelNameValid(name)
|
||||
}
|
||||
|
||||
function isActorPrivateKeyValid (privateKey: string) {
|
||||
return exists(privateKey) &&
|
||||
typeof privateKey === 'string' &&
|
||||
|
@ -9,6 +9,7 @@ import { isActivityPubUrlValid } from '../../helpers/custom-validators/activityp
|
||||
import { CONSTRAINTS_FIELDS } from '../../initializers'
|
||||
import { AccountModel } from '../account/account'
|
||||
import { ActorModel } from '../activitypub/actor'
|
||||
import { AvatarModel } from '../avatar/avatar'
|
||||
import { ServerModel } from '../server/server'
|
||||
import { getSort, throwIfNotValid } from '../utils'
|
||||
import { VideoModel } from './video'
|
||||
@ -46,6 +47,10 @@ enum ScopeNames {
|
||||
{
|
||||
model: () => ServerModel,
|
||||
required: false
|
||||
},
|
||||
{
|
||||
model: () => AvatarModel,
|
||||
required: false
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -243,10 +248,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
|
||||
createdAt: this.createdAt,
|
||||
updatedAt: this.updatedAt,
|
||||
totalReplies: this.get('totalReplies') || 0,
|
||||
account: {
|
||||
name: this.Account.name,
|
||||
host: this.Account.Actor.getHost()
|
||||
}
|
||||
account: this.Account.toFormattedJSON()
|
||||
} as VideoComment
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,11 @@
|
||||
import * as chai from 'chai'
|
||||
import 'mocha'
|
||||
import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
|
||||
import { dateIsValid, flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers, uploadVideo } from '../../utils/index'
|
||||
import { testVideoImage } from '../../utils'
|
||||
import {
|
||||
dateIsValid, flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers, updateMyAvatar,
|
||||
uploadVideo
|
||||
} from '../../utils/index'
|
||||
import {
|
||||
addVideoCommentReply, addVideoCommentThread, getVideoCommentThreads,
|
||||
getVideoThreadComments
|
||||
@ -29,6 +33,12 @@ describe('Test video comments', function () {
|
||||
const res = await uploadVideo(server.url, server.accessToken, {})
|
||||
videoUUID = res.body.video.uuid
|
||||
videoId = res.body.video.id
|
||||
|
||||
await updateMyAvatar({
|
||||
url: server.url,
|
||||
accessToken: server.accessToken,
|
||||
fixture: 'avatar.png'
|
||||
})
|
||||
})
|
||||
|
||||
it('Should not have threads on this video', async function () {
|
||||
@ -70,6 +80,10 @@ describe('Test video comments', function () {
|
||||
expect(comment.id).to.equal(comment.threadId)
|
||||
expect(comment.account.name).to.equal('root')
|
||||
expect(comment.account.host).to.equal('localhost:9001')
|
||||
|
||||
const test = await testVideoImage(server.url, 'avatar-resized', comment.account.avatar.path, '.png')
|
||||
expect(test).to.equal(true)
|
||||
|
||||
expect(comment.totalReplies).to.equal(0)
|
||||
expect(dateIsValid(comment.createdAt as string)).to.be.true
|
||||
expect(dateIsValid(comment.updatedAt as string)).to.be.true
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { Account } from '../actors'
|
||||
|
||||
export interface VideoComment {
|
||||
id: number
|
||||
url: string
|
||||
@ -8,10 +10,7 @@ export interface VideoComment {
|
||||
createdAt: Date | string
|
||||
updatedAt: Date | string
|
||||
totalReplies: number
|
||||
account: {
|
||||
name: string
|
||||
host: string
|
||||
}
|
||||
account: Account
|
||||
}
|
||||
|
||||
export interface VideoCommentThreadTree {
|
||||
|
Loading…
Reference in New Issue
Block a user