Multi step registration
This commit is contained in:
parent
e590b4a512
commit
1d5342abc4
|
@ -14,9 +14,6 @@
|
|||
|
||||
input {
|
||||
@include peertube-checkbox(1px);
|
||||
|
||||
width: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
|
|||
import { SortMeta } from 'primeng/api'
|
||||
import { BytesPipe } from 'ngx-pipes'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { UserRegister } from '@shared/models/users/user-register.model'
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
|
@ -64,7 +65,7 @@ export class UserService {
|
|||
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||
}
|
||||
|
||||
signup (userCreate: UserCreate) {
|
||||
signup (userCreate: UserRegister) {
|
||||
return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate)
|
||||
.pipe(
|
||||
map(this.restExtractor.extractDataBool),
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<section class="container">
|
||||
<header>
|
||||
<ng-container *ngFor="let step of steps; let i = index; let isLast = last;">
|
||||
<div
|
||||
class="step-info" [ngClass]="{ active: selectedIndex === i, completed: isCompleted(step) }"
|
||||
(click)="onClick(i)"
|
||||
>
|
||||
<div class="step-index">
|
||||
<ng-container *ngIf="!isCompleted(step)">{{ i + 1 }}</ng-container>
|
||||
<my-global-icon *ngIf="isCompleted(step)" iconName="tick"></my-global-icon>
|
||||
</div>
|
||||
|
||||
<div class="step-label">{{ step.label }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Do no display if this is the last child -->
|
||||
<div *ngIf="!isLast" class="connector"></div>
|
||||
</ng-container>
|
||||
</header>
|
||||
|
||||
<div [style.display]="selected ? 'block' : 'none'">
|
||||
<ng-container [ngTemplateOutlet]="selected.content"></ng-container>
|
||||
</div>
|
||||
|
||||
</section>
|
|
@ -0,0 +1,66 @@
|
|||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
$grey-color: #9CA3AB;
|
||||
$index-block-height: 32px;
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 15px;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.step-info {
|
||||
color: $grey-color;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: $index-block-height;
|
||||
|
||||
.step-index {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: $index-block-height;
|
||||
height: $index-block-height;
|
||||
border-radius: 100px;
|
||||
border: 2px solid $grey-color;
|
||||
margin-bottom: 10px;
|
||||
|
||||
my-global-icon {
|
||||
@include apply-svg-color(var(--mainBackgroundColor));
|
||||
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.step-label {
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
&.active,
|
||||
&.completed {
|
||||
.step-index {
|
||||
border-color: var(--mainColor);
|
||||
background-color: var(--mainColor);
|
||||
color: var(--mainBackgroundColor);
|
||||
}
|
||||
|
||||
.step-label {
|
||||
color: var(--mainColor);
|
||||
}
|
||||
}
|
||||
|
||||
&.completed {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.connector {
|
||||
flex: auto;
|
||||
margin: $index-block-height/2 10px 0 10px;
|
||||
height: 2px;
|
||||
background-color: $grey-color;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import { Component } from '@angular/core'
|
||||
import { CdkStep, CdkStepper } from '@angular/cdk/stepper'
|
||||
|
||||
@Component({
|
||||
selector: 'my-custom-stepper',
|
||||
templateUrl: './custom-stepper.component.html',
|
||||
styleUrls: [ './custom-stepper.component.scss' ],
|
||||
providers: [ { provide: CdkStepper, useExisting: CustomStepperComponent } ]
|
||||
})
|
||||
export class CustomStepperComponent extends CdkStepper {
|
||||
|
||||
onClick (index: number): void {
|
||||
this.selectedIndex = index
|
||||
}
|
||||
|
||||
isCompleted (step: CdkStep) {
|
||||
return step.stepControl && step.stepControl.dirty && step.stepControl.valid
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<form role="form" [formGroup]="form">
|
||||
|
||||
<div class="channel-explanations">
|
||||
<p i18n>
|
||||
A channel is an entity in which you upload your videos. Creating several of them helps you to organize and separate your content.<br />
|
||||
For example, you could decide to have a channel to publish your piano concerts, and another channel in which you publish your videos talking about ecology.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Other users can decide to subscribe any channel they want, to be notified when you publish a new video.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name" i18n>Channel name</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text" id="name" i18n-placeholder placeholder="Example: my_super_channel"
|
||||
formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }"
|
||||
>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">@{{ instanceHost }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="formErrors.name" class="form-error">
|
||||
{{ formErrors.name }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="isSameThanUsername()" class="form-error" i18n>
|
||||
Channel name cannot be the same than your account name. You can click on the first step to update your account name.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="displayName" i18n>Channel display name</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text" id="displayName"
|
||||
formControlName="displayName" [ngClass]="{ 'input-error': formErrors['displayName'] }"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div *ngIf="formErrors.displayName" class="form-error">
|
||||
{{ formErrors.displayName }}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,40 @@
|
|||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
|
||||
import { AuthService } from '@app/core'
|
||||
import { FormReactive, VideoChannelValidatorsService } from '../shared'
|
||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||
import { FormGroup } from '@angular/forms'
|
||||
|
||||
@Component({
|
||||
selector: 'my-signup-step-channel',
|
||||
templateUrl: './signup-step-channel.component.html',
|
||||
styleUrls: [ './signup.component.scss' ]
|
||||
})
|
||||
export class SignupStepChannelComponent extends FormReactive implements OnInit {
|
||||
@Input() username: string
|
||||
@Output() formBuilt = new EventEmitter<FormGroup>()
|
||||
|
||||
constructor (
|
||||
protected formValidatorService: FormValidatorService,
|
||||
private authService: AuthService,
|
||||
private videoChannelValidatorsService: VideoChannelValidatorsService
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
get instanceHost () {
|
||||
return window.location.host
|
||||
}
|
||||
|
||||
isSameThanUsername () {
|
||||
return this.username && this.username === this.form.value['name']
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.buildForm({
|
||||
name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME,
|
||||
displayName: this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME
|
||||
})
|
||||
|
||||
setTimeout(() => this.formBuilt.emit(this.form))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<form role="form" [formGroup]="form">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="username" i18n>Username</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text" id="username" i18n-placeholder placeholder="Example: jane_doe"
|
||||
formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
|
||||
>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">@{{ instanceHost }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="formErrors.username" class="form-error">
|
||||
{{ formErrors.username }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email" i18n>Email</label>
|
||||
<input
|
||||
type="text" id="email" i18n-placeholder placeholder="Email"
|
||||
formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.email" class="form-error">
|
||||
{{ formErrors.email }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password" i18n>Password</label>
|
||||
<input
|
||||
type="password" id="password" i18n-placeholder placeholder="Password"
|
||||
formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.password" class="form-error">
|
||||
{{ formErrors.password }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-terms">
|
||||
<my-peertube-checkbox
|
||||
inputName="terms" formControlName="terms"
|
||||
i18n-labelHtml
|
||||
labelHtml="I am at least 16 years old and agree to the <a href='/about/instance#terms-section' target='_blank'rel='noopener noreferrer'>Terms</a> of this instance"
|
||||
></my-peertube-checkbox>
|
||||
|
||||
<div *ngIf="formErrors.terms" class="form-error">
|
||||
{{ formErrors.terms }}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,37 @@
|
|||
import { Component, EventEmitter, OnInit, Output } from '@angular/core'
|
||||
import { AuthService } from '@app/core'
|
||||
import { FormReactive, UserValidatorsService } from '../shared'
|
||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||
import { FormGroup } from '@angular/forms'
|
||||
|
||||
@Component({
|
||||
selector: 'my-signup-step-user',
|
||||
templateUrl: './signup-step-user.component.html',
|
||||
styleUrls: [ './signup.component.scss' ]
|
||||
})
|
||||
export class SignupStepUserComponent extends FormReactive implements OnInit {
|
||||
@Output() formBuilt = new EventEmitter<FormGroup>()
|
||||
|
||||
constructor (
|
||||
protected formValidatorService: FormValidatorService,
|
||||
private authService: AuthService,
|
||||
private userValidatorsService: UserValidatorsService
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
get instanceHost () {
|
||||
return window.location.host
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.buildForm({
|
||||
username: this.userValidatorsService.USER_USERNAME,
|
||||
password: this.userValidatorsService.USER_PASSWORD,
|
||||
email: this.userValidatorsService.USER_EMAIL,
|
||||
terms: this.userValidatorsService.USER_TERMS
|
||||
})
|
||||
|
||||
setTimeout(() => this.formBuilt.emit(this.form))
|
||||
}
|
||||
}
|
|
@ -4,64 +4,35 @@
|
|||
Create an account
|
||||
</div>
|
||||
|
||||
|
||||
<my-success *ngIf="signupDone"></my-success>
|
||||
<div *ngIf="info" class="alert alert-info">{{ info }}</div>
|
||||
<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
|
||||
<div *ngIf="success" class="alert alert-success">{{ success }}</div>
|
||||
|
||||
<div class="d-flex justify-content-left flex-wrap">
|
||||
<form role="form" (ngSubmit)="signup()" [formGroup]="form">
|
||||
<div class="form-group">
|
||||
<label for="username" i18n>Username</label>
|
||||
<div class="wrapper" *ngIf="!signupDone">
|
||||
<div>
|
||||
<my-custom-stepper linear *ngIf="!signupDone">
|
||||
<cdk-step [stepControl]="formStepUser" i18n-label label="User information">
|
||||
<my-signup-step-user (formBuilt)="onUserFormBuilt($event)"></my-signup-step-user>
|
||||
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text" id="username" i18n-placeholder placeholder="Example: jane_doe"
|
||||
formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
|
||||
<button i18n cdkStepperNext [disabled]="!formStepUser || !formStepUser.valid">Next</button>
|
||||
</cdk-step>
|
||||
|
||||
<cdk-step [stepControl]="formStepChannel" i18n-label label="Channel information">
|
||||
<my-signup-step-channel (formBuilt)="onChannelFormBuilt($event)" [username]="getUsername()"></my-signup-step-channel>
|
||||
|
||||
<button i18n cdkStepperNext (click)="signup()"
|
||||
[disabled]="!formStepChannel || !formStepChannel.valid || hasSameChannelAndAccountNames()"
|
||||
>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">@{{ instanceHost }}</span>
|
||||
</div>
|
||||
</div>
|
||||
Create my account
|
||||
</button>
|
||||
</cdk-step>
|
||||
|
||||
<div *ngIf="formErrors.username" class="form-error">
|
||||
{{ formErrors.username }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email" i18n>Email</label>
|
||||
<input
|
||||
type="text" id="email" i18n-placeholder placeholder="Email"
|
||||
formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.email" class="form-error">
|
||||
{{ formErrors.email }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password" i18n>Password</label>
|
||||
<input
|
||||
type="password" id="password" i18n-placeholder placeholder="Password"
|
||||
formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.password" class="form-error">
|
||||
{{ formErrors.password }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-terms">
|
||||
<my-peertube-checkbox
|
||||
inputName="terms" formControlName="terms"
|
||||
i18n-labelHtml labelHtml="I am at least 16 years old and agree to the <a href='/about/instance#terms-section' target='_blank'rel='noopener noreferrer'>Terms</a> of this instance"
|
||||
></my-peertube-checkbox>
|
||||
|
||||
<div *ngIf="formErrors.terms" class="form-error">
|
||||
{{ formErrors.terms }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="submit" i18n-value value="Signup" [disabled]="!form.valid || signupDone">
|
||||
</form>
|
||||
<cdk-step i18n-label label="Done" editable="false">
|
||||
<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
|
||||
</cdk-step>
|
||||
</my-custom-stepper>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label i18n>Features found on this instance</label>
|
||||
|
|
|
@ -1,16 +1,32 @@
|
|||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
.alert {
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
& > div {
|
||||
margin-bottom: 40px;
|
||||
width: 450px;
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my-instance-features-table {
|
||||
display: block;
|
||||
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
form {
|
||||
margin: 0 60px 40px 0;
|
||||
}
|
||||
|
||||
.form-group-terms {
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
@ -25,15 +41,18 @@ form {
|
|||
|
||||
input:not([type=submit]) {
|
||||
@include peertube-input-text(400px);
|
||||
|
||||
display: block;
|
||||
|
||||
&#username {
|
||||
width: auto;
|
||||
&#username,
|
||||
&#name {
|
||||
width: auto !important;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
input[type=submit] {
|
||||
input[type=submit],
|
||||
button {
|
||||
@include peertube-button;
|
||||
@include orange-button;
|
||||
}
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
import { Component, OnInit } from '@angular/core'
|
||||
import { Component } from '@angular/core'
|
||||
import { AuthService, Notifier, RedirectService, ServerService } from '@app/core'
|
||||
import { UserCreate } from '../../../../shared'
|
||||
import { FormReactive, UserService, UserValidatorsService } from '../shared'
|
||||
import { UserService, UserValidatorsService } from '../shared'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||
import { UserRegister } from '@shared/models/users/user-register.model'
|
||||
import { FormGroup } from '@angular/forms'
|
||||
|
||||
@Component({
|
||||
selector: 'my-signup',
|
||||
templateUrl: './signup.component.html',
|
||||
styleUrls: [ './signup.component.scss' ]
|
||||
})
|
||||
export class SignupComponent extends FormReactive implements OnInit {
|
||||
export class SignupComponent {
|
||||
info: string = null
|
||||
error: string = null
|
||||
success: string = null
|
||||
signupDone = false
|
||||
|
||||
formStepUser: FormGroup
|
||||
formStepChannel: FormGroup
|
||||
|
||||
constructor (
|
||||
protected formValidatorService: FormValidatorService,
|
||||
private authService: AuthService,
|
||||
private userValidatorsService: UserValidatorsService,
|
||||
private notifier: Notifier,
|
||||
|
@ -25,47 +28,55 @@ export class SignupComponent extends FormReactive implements OnInit {
|
|||
private redirectService: RedirectService,
|
||||
private i18n: I18n
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
get instanceHost () {
|
||||
return window.location.host
|
||||
}
|
||||
|
||||
get requiresEmailVerification () {
|
||||
return this.serverService.getConfig().signup.requiresEmailVerification
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.buildForm({
|
||||
username: this.userValidatorsService.USER_USERNAME,
|
||||
password: this.userValidatorsService.USER_PASSWORD,
|
||||
email: this.userValidatorsService.USER_EMAIL,
|
||||
terms: this.userValidatorsService.USER_TERMS
|
||||
})
|
||||
hasSameChannelAndAccountNames () {
|
||||
return this.getUsername() === this.getChannelName()
|
||||
}
|
||||
|
||||
getUsername () {
|
||||
if (!this.formStepUser) return undefined
|
||||
|
||||
return this.formStepUser.value['username']
|
||||
}
|
||||
|
||||
getChannelName () {
|
||||
if (!this.formStepChannel) return undefined
|
||||
|
||||
return this.formStepChannel.value['name']
|
||||
}
|
||||
|
||||
onUserFormBuilt (form: FormGroup) {
|
||||
this.formStepUser = form
|
||||
}
|
||||
|
||||
onChannelFormBuilt (form: FormGroup) {
|
||||
this.formStepChannel = form
|
||||
}
|
||||
|
||||
signup () {
|
||||
this.error = null
|
||||
|
||||
const userCreate: UserCreate = this.form.value
|
||||
const body: UserRegister = Object.assign(this.formStepUser.value, this.formStepChannel.value)
|
||||
|
||||
this.userService.signup(userCreate).subscribe(
|
||||
this.userService.signup(body).subscribe(
|
||||
() => {
|
||||
this.signupDone = true
|
||||
|
||||
if (this.requiresEmailVerification) {
|
||||
this.info = this.i18n('Welcome! Now please check your emails to verify your account and complete signup.')
|
||||
this.info = this.i18n('Now please check your emails to verify your account and complete signup.')
|
||||
return
|
||||
}
|
||||
|
||||
// Auto login
|
||||
this.authService.login(userCreate.username, userCreate.password)
|
||||
this.authService.login(body.username, body.password)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('You are now logged in as {{username}}!', { username: userCreate.username }))
|
||||
|
||||
this.redirectService.redirectToHomepage()
|
||||
this.success = this.i18n('You are now logged in as {{username}}!', { username: body.username })
|
||||
},
|
||||
|
||||
err => this.error = err.message
|
||||
|
|
|
@ -1,17 +1,26 @@
|
|||
import { NgModule } from '@angular/core'
|
||||
|
||||
import { SignupRoutingModule } from './signup-routing.module'
|
||||
import { SignupComponent } from './signup.component'
|
||||
import { SharedModule } from '../shared'
|
||||
import { CdkStepperModule } from '@angular/cdk/stepper'
|
||||
import { SignupStepChannelComponent } from '@app/signup/signup-step-channel.component'
|
||||
import { SignupStepUserComponent } from '@app/signup/signup-step-user.component'
|
||||
import { CustomStepperComponent } from '@app/signup/custom-stepper.component'
|
||||
import { SuccessComponent } from '@app/signup/success.component'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
SignupRoutingModule,
|
||||
SharedModule
|
||||
SharedModule,
|
||||
CdkStepperModule
|
||||
],
|
||||
|
||||
declarations: [
|
||||
SignupComponent
|
||||
SignupComponent,
|
||||
CustomStepperComponent,
|
||||
SuccessComponent,
|
||||
SignupStepChannelComponent,
|
||||
SignupStepUserComponent
|
||||
],
|
||||
|
||||
exports: [
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<!-- Thanks: Amit Singh Sansoya from https://codepen.io/amit3200/pen/zWMJOO -->
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130.2 130.2">
|
||||
<circle class="path circle" fill="none" stroke="#73AF55" stroke-width="6" stroke-miterlimit="10" cx="65.1" cy="65.1" r="62.1"/>
|
||||
<polyline class="path check" fill="none" stroke="#73AF55" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" points="100.2,40.2 51.5,88.8 29.8,67.5 "/>
|
||||
</svg>
|
||||
|
||||
<p class="success">Welcome on PeerTube!</p>
|
After Width: | Height: | Size: 510 B |
|
@ -0,0 +1,74 @@
|
|||
svg {
|
||||
width: 100px;
|
||||
display: block;
|
||||
margin: 40px auto 0;
|
||||
}
|
||||
|
||||
.path {
|
||||
stroke-dasharray: 1000;
|
||||
stroke-dashoffset: 0;
|
||||
|
||||
&.circle {
|
||||
-webkit-animation: dash .9s ease-in-out;
|
||||
animation: dash .9s ease-in-out;
|
||||
}
|
||||
|
||||
&.line {
|
||||
stroke-dashoffset: 1000;
|
||||
-webkit-animation: dash .9s .35s ease-in-out forwards;
|
||||
animation: dash .9s .35s ease-in-out forwards;
|
||||
}
|
||||
|
||||
&.check {
|
||||
stroke-dashoffset: -100;
|
||||
-webkit-animation: dash-check .9s .35s ease-in-out forwards;
|
||||
animation: dash-check .9s .35s ease-in-out forwards;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
margin: 20px 0 60px;
|
||||
font-size: 1.25em;
|
||||
|
||||
&.success {
|
||||
color: #73AF55;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@-webkit-keyframes dash {
|
||||
0% {
|
||||
stroke-dashoffset: 1000;
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dash {
|
||||
0% {
|
||||
stroke-dashoffset: 1000;
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes dash-check {
|
||||
0% {
|
||||
stroke-dashoffset: -100;
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: 900;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dash-check {
|
||||
0% {
|
||||
stroke-dashoffset: -100;
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: 900;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core'
|
||||
|
||||
@Component({
|
||||
selector: 'my-success',
|
||||
templateUrl: './success.component.html',
|
||||
styleUrls: [ './success.component.scss' ]
|
||||
})
|
||||
export class SuccessComponent {
|
||||
|
||||
}
|
|
@ -331,7 +331,12 @@
|
|||
}
|
||||
|
||||
@mixin peertube-checkbox ($border-width) {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
|
||||
&:focus + span {
|
||||
outline: auto;
|
||||
}
|
||||
|
||||
& + span {
|
||||
position: relative;
|
||||
|
|
|
@ -70,6 +70,12 @@ const usersRegisterValidator = [
|
|||
.end()
|
||||
}
|
||||
|
||||
if (body.channel.name === body.username) {
|
||||
return res.status(400)
|
||||
.send({ error: 'Channel name cannot be the same than user username.' })
|
||||
.end()
|
||||
}
|
||||
|
||||
const existing = await ActorModel.loadLocalByName(body.channel.name)
|
||||
if (existing) {
|
||||
return res.status(409)
|
||||
|
|
|
@ -737,6 +737,13 @@ describe('Test users API validators', function () {
|
|||
await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a channel name that is the same than user username', async function () {
|
||||
const source = { username: 'super_user', channel: { name: 'super_user', displayName: 'display name' } }
|
||||
const fields = immutableAssign(baseCorrectParams, source)
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an existing channel', async function () {
|
||||
const videoChannelAttributesArg = { name: 'existing_channel', displayName: 'hello', description: 'super description' }
|
||||
await addVideoChannel(server.url, server.accessToken, videoChannelAttributesArg)
|
||||
|
|
Loading…
Reference in New Issue