upgrade to newest backend
This commit is contained in:
parent
e6742f1cc5
commit
72178dd7c4
@ -4,7 +4,7 @@ import {Routes, RouterModule} from '@angular/router';
|
||||
import {AuthGuard, AuthUpdateGuard, AuthenticatedGuard, AnonymousGuard} from './auth/auth.guard';
|
||||
import {ImprintComponent, PrivacyPolicyComponent, TermsOfServiceComponent} from './pages/general/general.component';
|
||||
import {FormLoginComponent} from './pages/form-login/form-login.component';
|
||||
import {FormLoginTotpComponent} from './pages/form-login-totp/form-login-totp.component';
|
||||
import {FormLogin2FAComponent} from './pages/form-login-2fa/form-login-2fa.component';
|
||||
import {PasswordComponent} from './pages/password/password.component';
|
||||
import {PasswordResetComponent} from './pages/password-reset/password-reset.component';
|
||||
import {AccountComponent} from './pages/account/account.component';
|
||||
@ -30,9 +30,9 @@ const routes: Routes = [
|
||||
{path: 'privacy-policy', component: PrivacyPolicyComponent, canActivate: [AuthUpdateGuard]},
|
||||
{path: 'terms-of-service', component: TermsOfServiceComponent, canActivate: [AuthUpdateGuard]},
|
||||
{path: 'login', component: FormLoginComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'login/totp', component: FormLoginTotpComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'login/2fa', component: FormLogin2FAComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'service-login', component: FormLoginComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'service-login/totp', component: FormLoginTotpComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'service-login/2fa', component: FormLogin2FAComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'password', component: PasswordComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'password-reset', component: PasswordResetComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'services', component: ServicesComponent, canActivate: [AuthenticatedGuard]},
|
||||
|
@ -18,9 +18,8 @@ import {AccountComponent} from './pages/account/account.component';
|
||||
import {ServicesComponent} from './pages/services/services.component';
|
||||
import {AppComponent} from './app.component';
|
||||
import {LoginComponent} from './pages/login/login.component';
|
||||
import {LoginTotpComponent} from './pages/login-totp/login-totp.component';
|
||||
import {FormLoginComponent} from './pages/form-login/form-login.component';
|
||||
import {FormLoginTotpComponent} from './pages/form-login-totp/form-login-totp.component';
|
||||
import {FormLogin2FAComponent} from './pages/form-login-2fa/form-login-2fa.component';
|
||||
import {TokensComponent} from './pages/tokens/tokens.component';
|
||||
import {InvitesComponent} from './pages/invites/invites.component';
|
||||
import {PermissionsComponent} from './ui/permissions/permissions.component';
|
||||
@ -73,9 +72,8 @@ export class XhrInterceptor implements HttpInterceptor {
|
||||
ImprintComponent, PrivacyPolicyComponent, TermsOfServiceComponent,
|
||||
AccountComponent,
|
||||
LoginComponent,
|
||||
LoginTotpComponent,
|
||||
FormLoginComponent,
|
||||
FormLoginTotpComponent,
|
||||
FormLogin2FAComponent,
|
||||
TokensComponent,
|
||||
InvitesComponent,
|
||||
ServicesComponent,
|
||||
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AccountComponent } from './account.component';
|
||||
|
||||
describe('AccountComponent', () => {
|
||||
let component: AccountComponent;
|
||||
let fixture: ComponentFixture<AccountComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ AccountComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AccountComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AliasesComponent } from './aliases.component';
|
||||
|
||||
describe('AliasesComponent', () => {
|
||||
let component: AliasesComponent;
|
||||
let fixture: ComponentFixture<AliasesComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ AliasesComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AliasesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DomainsComponent } from './domains.component';
|
||||
|
||||
describe('DomainsComponent', () => {
|
||||
let component: DomainsComponent;
|
||||
let fixture: ComponentFixture<DomainsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DomainsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DomainsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { InfoComponent } from './info.component';
|
||||
|
||||
describe('InfoComponent', () => {
|
||||
let component: InfoComponent;
|
||||
let fixture: ComponentFixture<InfoComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ InfoComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(InfoComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {ProfileComponent} from './profile.component';
|
||||
|
||||
describe('ProfileComponent', () => {
|
||||
let component: ProfileComponent;
|
||||
let fixture: ComponentFixture<ProfileComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ProfileComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProfileComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SecurityComponent } from './security.component';
|
||||
|
||||
describe('SecurityComponent', () => {
|
||||
let component: SecurityComponent;
|
||||
let fixture: ComponentFixture<SecurityComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ SecurityComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SecurityComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -2,7 +2,7 @@ import {Component, OnInit, ViewChild, Inject} from '@angular/core';
|
||||
import {FormBuilder, FormGroup, FormControl, Validators, NgForm} from '@angular/forms';
|
||||
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
|
||||
|
||||
import {AuthService} from './../../../services/auth.service';
|
||||
import {Auth2FAService} from './../../../services/auth.2fa.service';
|
||||
import {UserService} from './../../../services/user.service';
|
||||
import {MatchingValidator} from './../../../utils/matching.validator';
|
||||
|
||||
@ -29,7 +29,7 @@ export class SecurityComponent implements OnInit {
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private userService: UserService,
|
||||
private authService: AuthService,
|
||||
private auth2FAService: Auth2FAService,
|
||||
public dialog: MatDialog) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -52,7 +52,7 @@ export class SecurityComponent implements OnInit {
|
||||
|
||||
})
|
||||
|
||||
this.authService.isTotpEnabled().subscribe(response => {
|
||||
this.auth2FAService.isEnabled('totp').subscribe(response => {
|
||||
this.totp = true;
|
||||
}, error => {
|
||||
this.totp = false;
|
||||
@ -99,7 +99,7 @@ export class SecurityComponent implements OnInit {
|
||||
}
|
||||
|
||||
createTotp() {
|
||||
this.authService.createTotp().subscribe((result: any) => {
|
||||
this.auth2FAService.create('totp').subscribe((result: any) => {
|
||||
const dialogRef = this.dialog.open(SecurityTotpDialog, {
|
||||
closeOnNavigation: false,
|
||||
disableClose: true,
|
||||
@ -108,11 +108,11 @@ export class SecurityComponent implements OnInit {
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if(result) {
|
||||
this.authService.enableTotp(result).subscribe((result: any) => {
|
||||
this.auth2FAService.enable('totp', result).subscribe((result: any) => {
|
||||
this.totp = true;
|
||||
})
|
||||
} else {
|
||||
this.authService.removeTotp().subscribe((result: any) => {
|
||||
this.auth2FAService.remove('totp').subscribe((result: any) => {
|
||||
this.totp = false;
|
||||
})
|
||||
}
|
||||
@ -130,7 +130,7 @@ export class SecurityComponent implements OnInit {
|
||||
}
|
||||
|
||||
removeTotp() {
|
||||
this.authService.removeTotp().subscribe((result: any) => {
|
||||
this.auth2FAService.remove('totp').subscribe((result: any) => {
|
||||
this.totp = false;
|
||||
})
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { VoucherComponent } from './voucher.component';
|
||||
|
||||
describe('VoucherComponent', () => {
|
||||
let component: VoucherComponent;
|
||||
let fixture: ComponentFixture<VoucherComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ VoucherComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(VoucherComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
39
src/app/pages/form-login-2fa/form-login-2fa.component.html
Normal file
39
src/app/pages/form-login-2fa/form-login-2fa.component.html
Normal file
@ -0,0 +1,39 @@
|
||||
<form action="{{apiUrl}}/auth/login/2fa" method="POST" #form2FA>
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<h2>{{'security.2fa.external' | i18n}}<mat-icon style="font-size: 1em;">open_in_new
|
||||
</mat-icon>
|
||||
</h2>
|
||||
<mat-error *ngIf="loginInvalid">
|
||||
{{'security.2fa.invalid' | i18n}}
|
||||
</mat-error>
|
||||
<input id="provider" name="provider" matInput hidden [value]="selectedProvider.id">
|
||||
<mat-select [(ngModel)]="selectedProvider" placeholder="{{'security.2fa.provider' | i18n}}"
|
||||
[ngModelOptions]="{standalone: true}">
|
||||
<mat-option *ngFor="let provider of providers" [value]="provider">
|
||||
{{'security.2fa.' + provider.id | i18n}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<a mat-raised-button (click)="request()"
|
||||
*ngIf="selectedProvider && selectedProvider.request">{{'security.2fa.' + selectedProvider.id +
|
||||
'.request'
|
||||
| i18n}}</a>
|
||||
<mat-form-field>
|
||||
<input id="code" name="code" matInput placeholder="{{'security.2fa.code' | i18n}}" required
|
||||
matAutofocus>
|
||||
<mat-error>
|
||||
{{'security.2fa.missing' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle id="keep" name="keep" [checked]="keep">
|
||||
{{'login.keepSession' | i18n}}
|
||||
</mat-slide-toggle>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button type="submit" mat-raised-button color="primary" (click)="form2FA.submit()"
|
||||
[disabled]="form2FA.invalid">{{'security.2fa.login' | i18n}}<mat-icon style="font-size: 1em;">
|
||||
open_in_new
|
||||
</mat-icon></button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</form>
|
@ -3,20 +3,25 @@ import {ActivatedRoute, Router} from '@angular/router';
|
||||
|
||||
import {environment} from '../../../environments/environment';
|
||||
|
||||
import {Auth2FAService} from '../../services/auth.2fa.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-form-login-totp',
|
||||
templateUrl: './form-login-totp.component.html',
|
||||
styleUrls: ['./form-login-totp.component.scss']
|
||||
selector: 'app-form-login-2fa',
|
||||
templateUrl: './form-login-2fa.component.html',
|
||||
styleUrls: ['./form-login-2fa.component.scss']
|
||||
})
|
||||
export class FormLoginTotpComponent implements OnInit {
|
||||
export class FormLogin2FAComponent implements OnInit {
|
||||
|
||||
loginInvalid: boolean;
|
||||
keep: boolean = false;
|
||||
apiUrl = environment.apiUrl;
|
||||
selectedProvider = {id: "", request: false};
|
||||
providers = [];
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute) {}
|
||||
private route: ActivatedRoute,
|
||||
private auth2FAService: Auth2FAService) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.route.queryParams.subscribe(params => {
|
||||
@ -29,8 +34,20 @@ export class FormLoginTotpComponent implements OnInit {
|
||||
this.router.navigate([], {queryParams: {keep: null}, queryParamsHandling: 'merge'});
|
||||
}
|
||||
});
|
||||
|
||||
this.auth2FAService.getEnabled().subscribe((providers: any) => {
|
||||
this.providers = providers;
|
||||
if(this.providers[0]) {
|
||||
this.selectedProvider = this.providers[0];
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
request() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<form action="{{apiUrl}}/auth/login/totp" method="POST" #totpForm>
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<h2>{{'security.2fa.totp.external' | i18n}}<mat-icon style="font-size: 1em;">open_in_new
|
||||
</mat-icon>
|
||||
</h2>
|
||||
<mat-error *ngIf="loginInvalid">
|
||||
{{'security.2fa.totp.invalid' | i18n}}
|
||||
</mat-error>
|
||||
<mat-form-field>
|
||||
<input id="code" name="code" matInput placeholder="{{'security.2fa.totp.code' | i18n}}" required matAutofocus>
|
||||
<mat-error>
|
||||
{{'security.2fa.totp.missing' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-slide-toggle id="keep" name="keep" [checked]="keep" >
|
||||
{{'login.keepSession' | i18n}}
|
||||
</mat-slide-toggle>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button type="submit" mat-raised-button color="primary" (click)="totpForm.submit()"
|
||||
[disabled]="totpForm.invalid">{{'security.2fa.totp.login' | i18n}}<mat-icon style="font-size: 1em;">
|
||||
open_in_new
|
||||
</mat-icon></button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</form>
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FormLoginTotpComponent } from './form-login-totp.component';
|
||||
|
||||
describe('FormLoginTotpComponent', () => {
|
||||
let component: FormLoginTotpComponent;
|
||||
let fixture: ComponentFixture<FormLoginTotpComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ FormLoginTotpComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FormLoginTotpComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FormLoginComponent } from './form-login.component';
|
||||
|
||||
describe('FormLoginComponent', () => {
|
||||
let component: FormLoginComponent;
|
||||
let fixture: ComponentFixture<FormLoginComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ FormLoginComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FormLoginComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { InvitesComponent } from './invites.component';
|
||||
|
||||
describe('InvitesComponent', () => {
|
||||
let component: InvitesComponent;
|
||||
let fixture: ComponentFixture<InvitesComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ InvitesComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(InvitesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { JitsiComponent } from './jitsi.component';
|
||||
|
||||
describe('JitsiComponent', () => {
|
||||
let component: JitsiComponent;
|
||||
let fixture: ComponentFixture<JitsiComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ JitsiComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(JitsiComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoginTotpComponent } from './login-totp.component';
|
||||
|
||||
describe('LoginTotpComponent', () => {
|
||||
let component: LoginTotpComponent;
|
||||
let fixture: ComponentFixture<LoginTotpComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ LoginTotpComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LoginTotpComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import {Auth2FAService} from '../../services/auth.2fa.service';
|
||||
import {Router, ActivatedRoute} from '@angular/router';
|
||||
|
||||
import {environment} from '../../../environments/environment';
|
||||
@ -17,7 +17,7 @@ export class LoginTotpComponent implements OnInit {
|
||||
public apiUrl = environment.apiUrl;
|
||||
targetRoute = '/account/info';
|
||||
|
||||
constructor(private formBuilder: FormBuilder, private authService: AuthService, private router: Router, private route: ActivatedRoute) { }
|
||||
constructor(private formBuilder: FormBuilder, private auth2FAService: Auth2FAService, private router: Router, private route: ActivatedRoute) {}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
@ -36,13 +36,7 @@ export class LoginTotpComponent implements OnInit {
|
||||
async loginTotp() {
|
||||
this.loginInvalid = false;
|
||||
if(this.form.valid) {
|
||||
|
||||
const totpModel = {
|
||||
code: this.form.get('code').value,
|
||||
keep: this.form.get('keep').value
|
||||
};
|
||||
|
||||
this.authService.loginTotp(totpModel).subscribe((response: any) => {
|
||||
this.auth2FAService.login('totp', this.form.get('code').value, this.form.get('keep').value).subscribe((response: any) => {
|
||||
this.router.navigate([this.targetRoute]);
|
||||
}, error => {
|
||||
this.loginInvalid = true;
|
||||
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoginComponent } from './login.component';
|
||||
|
||||
describe('LoginComponent', () => {
|
||||
let component: LoginComponent;
|
||||
let fixture: ComponentFixture<LoginComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ LoginComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LoginComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NotfoundComponent } from './notfound.component';
|
||||
|
||||
describe('NotfoundComponent', () => {
|
||||
let component: NotfoundComponent;
|
||||
let fixture: ComponentFixture<NotfoundComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ NotfoundComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(NotfoundComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PasswordResetComponent } from './password-reset.component';
|
||||
|
||||
describe('PasswordResetComponent', () => {
|
||||
let component: PasswordResetComponent;
|
||||
let fixture: ComponentFixture<PasswordResetComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ PasswordResetComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PasswordResetComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PasswordComponent } from './password.component';
|
||||
|
||||
describe('PasswordComponent', () => {
|
||||
let component: PasswordComponent;
|
||||
let fixture: ComponentFixture<PasswordComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ PasswordComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PasswordComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RegisterComponent } from './register.component';
|
||||
|
||||
describe('RegisterComponent', () => {
|
||||
let component: RegisterComponent;
|
||||
let fixture: ComponentFixture<RegisterComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ RegisterComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RegisterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ServicesComponent } from './services.component';
|
||||
|
||||
describe('ServicesComponent', () => {
|
||||
let component: ServicesComponent;
|
||||
let fixture: ComponentFixture<ServicesComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ServicesComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ServicesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TokensComponent } from './tokens.component';
|
||||
|
||||
describe('TokensComponent', () => {
|
||||
let component: TokensComponent;
|
||||
let fixture: ComponentFixture<TokensComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ TokensComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TokensComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UnavailableComponent } from './unavailable.component';
|
||||
|
||||
describe('UnavailableComponent', () => {
|
||||
let component: UnavailableComponent;
|
||||
let fixture: ComponentFixture<UnavailableComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ UnavailableComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(UnavailableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -2,7 +2,7 @@
|
||||
<mat-progress-bar *ngIf="!success && !error" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<div *ngIf="success">
|
||||
<h3>{{model.username}}</h3>
|
||||
<h3>{{model.username}} <small *ngIf="isMe">{{'user.isMe' | i18n}}</small></h3>
|
||||
<app-profilefields [username]="model.username"></app-profilefields>
|
||||
<div *ngIf="model.aliases && model.aliases.length > 0">
|
||||
<h4>{{'user.aliases' | i18n}}</h4>
|
||||
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UserComponent } from './user.component';
|
||||
|
||||
describe('UserComponent', () => {
|
||||
let component: UserComponent;
|
||||
let fixture: ComponentFixture<UserComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ UserComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(UserComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -2,6 +2,7 @@ import {Component, OnInit} from '@angular/core';
|
||||
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
|
||||
import {AuthService} from '../../services/auth.service';
|
||||
import {ProfileService} from '../../services/profile.service';
|
||||
|
||||
@Component({
|
||||
@ -14,8 +15,10 @@ export class UserComponent implements OnInit {
|
||||
model: any;
|
||||
error = false;
|
||||
success = false;
|
||||
isMe = false;
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private profileService: ProfileService,
|
||||
private route: ActivatedRoute) {}
|
||||
|
||||
@ -27,6 +30,12 @@ export class UserComponent implements OnInit {
|
||||
}, error => {
|
||||
this.error = error;
|
||||
})
|
||||
|
||||
this.authService.auth.subscribe((auth: any) => {
|
||||
this.isMe = auth && auth.principal && auth.principal.username == this.username;
|
||||
console.log(this.isMe, auth);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
45
src/app/services/auth.2fa.service.ts
Normal file
45
src/app/services/auth.2fa.service.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
||||
|
||||
import {environment} from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class Auth2FAService {
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
getEnabled() {
|
||||
return this.http.get(environment.apiUrl + "/auth/2fa");
|
||||
}
|
||||
|
||||
getAvailable() {
|
||||
return this.http.get(environment.apiUrl + "/auth/2fa/available");
|
||||
}
|
||||
|
||||
isEnabled(provider) {
|
||||
return this.http.get(environment.apiUrl + "/auth/2fa/" + provider);
|
||||
}
|
||||
|
||||
create(provider) {
|
||||
return this.http.put(environment.apiUrl + "/auth/2fa/" + provider, {});
|
||||
}
|
||||
|
||||
enable(provider, code) {
|
||||
return this.http.patch(environment.apiUrl + "/auth/2fa/" + provider, code);
|
||||
}
|
||||
|
||||
remove(provider) {
|
||||
return this.http.delete(environment.apiUrl + "/auth/2fa/" + provider);
|
||||
}
|
||||
|
||||
login(provider, code, keep) {
|
||||
return this.http.post(environment.apiUrl + "/auth/login/2fa", {
|
||||
'provider': provider,
|
||||
'code': code,
|
||||
'keep': keep
|
||||
});
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import { BehaviorSubject, of } from 'rxjs';
|
||||
import {ReplaySubject, of} from 'rxjs';
|
||||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
||||
|
||||
import {environment} from './../../environments/environment';
|
||||
@ -9,7 +9,7 @@ import { environment } from './../../environments/environment';
|
||||
})
|
||||
export class AuthService {
|
||||
|
||||
auth: BehaviorSubject<any> = new BehaviorSubject(undefined);
|
||||
auth: ReplaySubject<any> = new ReplaySubject(undefined);
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
@ -44,24 +44,4 @@ export class AuthService {
|
||||
const headers = new HttpHeaders().set('Content-Type', 'text/plain; charset=utf-8');
|
||||
return this.http.post(environment.apiUrl + "/auth/password/reset", model);
|
||||
}
|
||||
|
||||
isTotpEnabled() {
|
||||
return this.http.get(environment.apiUrl + "/auth/totp");
|
||||
}
|
||||
|
||||
createTotp() {
|
||||
return this.http.put(environment.apiUrl + "/auth/totp", {});
|
||||
}
|
||||
|
||||
enableTotp(code) {
|
||||
return this.http.patch(environment.apiUrl + "/auth/totp", code);
|
||||
}
|
||||
|
||||
removeTotp() {
|
||||
return this.http.delete(environment.apiUrl + "/auth/totp");
|
||||
}
|
||||
|
||||
loginTotp(totpModel) {
|
||||
return this.http.post(environment.apiUrl + "/auth/login/totp", totpModel);
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PermissionsComponent } from './permissions.component';
|
||||
|
||||
describe('PermissionsComponent', () => {
|
||||
let component: PermissionComponent;
|
||||
let fixture: ComponentFixture<PermissionComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ PermissionsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PermissionsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -29,7 +29,7 @@ export class ProfileFieldPgpBlob implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.authService.getAuth().then((auth: any) => {
|
||||
this.authService.auth.subscribe((auth: any) => {
|
||||
if(!auth.authenticated) {
|
||||
return;
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {ProfileFieldsComponent} from './profilefields.component';
|
||||
|
||||
describe('ProfileFieldsComponent', () => {
|
||||
let component: ProfileFieldsComponent;
|
||||
let fixture: ComponentFixture<ProfileFieldsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ProfileFieldsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProfileFieldsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { QuotasComponent } from './quotas.component';
|
||||
|
||||
describe('QuotasComponent', () => {
|
||||
let component: QuotasComponent;
|
||||
let fixture: ComponentFixture<QuotasComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ QuotasComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(QuotasComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -878,6 +878,117 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4 id="PeerTube">Nutzung des Dienstes PeerTube <small>tube.bstly.de</small></h4>
|
||||
|
||||
<h5>Gespeicherte Daten</h5>
|
||||
|
||||
<p>Die folgenden Daten werden durch den Dienst PeerTube erfasst:
|
||||
<p>
|
||||
|
||||
<table border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Bezeichnung</th>
|
||||
<th>Betroffene Benutzer </th>
|
||||
<th>Speicherfrist</th>
|
||||
<th>Verwendungszweck</th>
|
||||
<th>Weitergabe an Dritte</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Streaming-Daten / IP-Addresse</strong>
|
||||
<p>P2P Video Funktionalität (<a href="https://tube.bstly.de/about/peertube#privacy">Details</a>)</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Alle Nutzer der Plattform mit aktiviertem Verteilsystem (Standard)</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Bis zum Leeren des Browser Caches</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Teilen von geschauten Videos über P2P mit anderen.</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Weitergabe an Dritte! Kann aktiv ausgeschaltet werden.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Account-Daten</strong>
|
||||
<p>Benutzername, E-Mail Adresse, Profildaten (freiwillig)</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Benutzer mit Account</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>bis zur Löschung</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Erstellen von Kanälen, Videos, Livestreams und Kommentaren.</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>einsehbar für andere Benutzer</p>
|
||||
<p>öffentlich einsehbar bei Aktivitäten in öffentlichen Kanälen</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Einstellungen/Kanäle</strong>
|
||||
<p>Eigene, favorisierte Kanäle</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Benutzer mit Account</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>bis zur Löschung</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Verwaltung der Kanälen, Nutzung der Plattform</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Weitergabe individuell vom Nutzer einstellbar</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Videos/Livestreams</strong>
|
||||
<p>Videos in den Kanälen</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Benutzer mit Account</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>siehe Einstellungen/Kanäle</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Hochladen von Videos in Kanäle, Bereitstellen der Videos für andere, Livestreams</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Abhängig von Sichtbarkeit der entsprechenden Kanäle/Videos/Livestreams, siehe Einstellungen/Kanäle</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Kommentare</strong>
|
||||
<p>Kommentare zu Videos</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Benutzer mit Account</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>siehe Einstellungen/ Kanäle</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Kommunikation über Inhalte</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Abhängig von Sichtbarkeit der entsprechenden Kanäle/Videos, siehe Einstellungen/Kanäle</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4 id="Gitea">Nutzung des Dienstes Gitea <small>git.bstly.de</small></h4>
|
||||
|
||||
|
@ -880,6 +880,117 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4 id="PeerTube">Nutzung des Dienstes PeerTube <small>tube.bstly.de</small></h4>
|
||||
|
||||
<h5>Gespeicherte Daten</h5>
|
||||
|
||||
<p>Die folgenden Daten werden durch den Dienst PeerTube erfasst:
|
||||
<p>
|
||||
|
||||
<table border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Bezeichnung</th>
|
||||
<th>Betroffene Benutzer </th>
|
||||
<th>Speicherfrist</th>
|
||||
<th>Verwendungszweck</th>
|
||||
<th>Weitergabe an Dritte</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Streaming-Daten / IP-Addresse</strong>
|
||||
<p>P2P Video Funktionalität (<a href="https://tube.bstly.de/about/peertube#privacy">Details</a>)</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Alle Nutzer der Plattform mit aktiviertem Verteilsystem (Standard)</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Bis zum Leeren des Browser Caches</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Teilen von geschauten Videos über P2P mit anderen.</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Weitergabe an Dritte! Kann aktiv ausgeschaltet werden.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Account-Daten</strong>
|
||||
<p>Benutzername, E-Mail Adresse, Profildaten (freiwillig)</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Benutzer mit Account</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>bis zur Löschung</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Erstellen von Kanälen, Videos, Livestreams und Kommentaren.</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>einsehbar für andere Benutzer</p>
|
||||
<p>öffentlich einsehbar bei Aktivitäten in öffentlichen Kanälen</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Einstellungen/Kanäle</strong>
|
||||
<p>Eigene, favorisierte Kanäle</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Benutzer mit Account</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>bis zur Löschung</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Verwaltung der Kanälen, Nutzung der Plattform</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Weitergabe individuell vom Nutzer einstellbar</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Videos/Livestreams</strong>
|
||||
<p>Videos in den Kanälen</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Benutzer mit Account</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>siehe Einstellungen/Kanäle</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Hochladen von Videos in Kanäle, Bereitstellen der Videos für andere, Livestreams</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Abhängig von Sichtbarkeit der entsprechenden Kanäle/Videos/Livestreams, siehe Einstellungen/Kanäle</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Kommentare</strong>
|
||||
<p>Kommentare zu Videos</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Benutzer mit Account</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>siehe Einstellungen/ Kanäle</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Kommunikation über Inhalte</p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Abhängig von Sichtbarkeit der entsprechenden Kanäle/Videos, siehe Einstellungen/Kanäle</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4 id="Gitea">Nutzung des Dienstes Gitea <small>git.bstly.de</small></h4>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user