This commit is contained in:
Lurkars 2021-03-11 19:52:37 +01:00
parent cf46cf6fd0
commit c4321d99cb
41 changed files with 1389 additions and 471 deletions

13
package-lock.json generated
View File

@ -799,6 +799,14 @@
"tslib": "^2.0.0"
}
},
"@angular/material-moment-adapter": {
"version": "10.2.7",
"resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-10.2.7.tgz",
"integrity": "sha512-VaigAiBCz10AvpzgZvdR4SCGnMRxXKx8ukUdeowuoqAFONEPpRdCJmwZ+8bpi9Q/jXlrZJicCMhklj4bBQw6tg==",
"requires": {
"tslib": "^2.0.0"
}
},
"@angular/platform-browser": {
"version": "10.1.5",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-10.1.5.tgz",
@ -8233,6 +8241,11 @@
"minimist": "^1.2.5"
}
},
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",

View File

@ -18,10 +18,12 @@
"@angular/core": "~10.1.5",
"@angular/forms": "~10.1.5",
"@angular/material": "^10.2.4",
"@angular/material-moment-adapter": "^10.2.7",
"@angular/platform-browser": "~10.1.5",
"@angular/platform-browser-dynamic": "~10.1.5",
"@angular/router": "~10.1.5",
"angularx-qrcode": "^10.0.11",
"moment": "^2.29.1",
"openpgp": "^4.10.8",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",

View File

@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard, AuthUpdateGuard, AuthenticatedGuard, AnonymousGuard } from './auth/auth.guard';
import { HomeComponent, ImprintComponent, PrivacyPolicyComponent } from './pages/home/home.component';
import { HomeComponent, ImprintComponent, PrivacyPolicyComponent, TermsOfServiceComponent } from './pages/home/home.component';
import { HomeClubComponent } from './pages/home/club/home-club.component';
import { HomeGeneralComponent } from './pages/home/general/home-general.component';
import { HomePrivacyComponent } from './pages/home/privacy/home-privacy.component';
@ -18,13 +18,14 @@ import { RegisterComponent } from './pages/register/register.component';
import { TokensComponent } from './pages/tokens/tokens.component';
import { AppsComponent } from './pages/apps/apps.component';
import { InfoComponent } from './pages/account/info/info.component';
import { ProfileComponent } from './pages/account/profile/profile.component';
import { VoucherComponent } from './pages/account/voucher/voucher.component';
import { SecurityComponent } from './pages/account/security/security.component';
import { UnavailableComponent } from './pages/unavailable/unavailable.component';
import { NotfoundComponent } from './pages/notfound/notfound.component';
const routes: Routes = [
{ path: '', redirectTo: "/general", pathMatch: 'full' },
{ path: '', redirectTo: "/account", pathMatch: 'full' },
{
path: '', component: HomeComponent, canActivate: [AuthUpdateGuard], runGuardsAndResolvers: 'always', children: [
{ path: 'general', component: HomeGeneralComponent, canActivate: [AuthUpdateGuard] },
@ -35,6 +36,7 @@ const routes: Routes = [
},
{ path: 'imprint', component: ImprintComponent, canActivate: [AuthUpdateGuard] },
{ path: 'privacy-policy', component: PrivacyPolicyComponent, canActivate: [AuthUpdateGuard] },
{ path: 'terms-of-service', component: TermsOfServiceComponent, canActivate: [AuthUpdateGuard] },
{ path: 'login', component: LoginComponent, canActivate: [AnonymousGuard] },
{ path: 'login/totp', component: LoginTotpComponent, canActivate: [AnonymousGuard] },
{ path: 'external-login', component: FormLoginComponent, canActivate: [AnonymousGuard] },
@ -46,6 +48,7 @@ const routes: Routes = [
path: 'account', component: AccountComponent, canActivate: [AuthenticatedGuard], children: [
{ path: 'info', component: InfoComponent, canActivate: [AuthenticatedGuard] },
{ path: 'profile', component: ProfileComponent, canActivate: [AuthenticatedGuard] },
{ path: 'voucher', component: VoucherComponent, canActivate: [AuthenticatedGuard] },
{ path: 'security', component: SecurityComponent, canActivate: [AuthenticatedGuard] }
]

View File

@ -24,9 +24,6 @@
<mat-sidenav #sidenav [mode]="isBiggerScreen() ? 'side' : 'over'" [(opened)]="opened"
(click)="!isBiggerScreen() && opened=false">
<mat-nav-list>
<a routerLink="/general" mat-list-item>
<mat-icon>home</mat-icon> {{'home' | i18n}}
</a>
<a *ngIf="!auth || auth && !auth.authenticated" routerLink="/login" routerLinkActive="active" mat-list-item>
<mat-icon>login</mat-icon> {{'login' | i18n}}
</a>

View File

@ -1,10 +1,11 @@
import { Component, HostListener } from '@angular/core';
import {Component, HostListener} from '@angular/core';
import { AuthService } from './services/auth.service';
import { I18nService } from './services/i18n.service';
import { Router } from '@angular/router';
import { DomSanitizer } from '@angular/platform-browser';
import { MatIconRegistry } from '@angular/material/icon';
import {AuthService} from './services/auth.service';
import {I18nService} from './services/i18n.service';
import {Router} from '@angular/router';
import {DomSanitizer} from '@angular/platform-browser';
import {MatIconRegistry} from '@angular/material/icon';
import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE} from '@angular/material/core';
@Component({
selector: 'app-root',
@ -19,19 +20,21 @@ export class AppComponent {
locales;
auth;
constructor(private i18n: I18nService, private authService: AuthService, private router: Router, private iconRegistry: MatIconRegistry, private sanitizer: DomSanitizer) {
constructor(private i18n: I18nService, private authService: AuthService, private router: Router, private iconRegistry: MatIconRegistry, private sanitizer: DomSanitizer, private _adapter: DateAdapter<any>) {
this.currentLocale = this.i18n.getLocale();
this.locales = this.i18n.getLocales();
this.authService.auth.subscribe(data => {
this.auth = data;
})
this._adapter.setLocale(this.currentLocale);
iconRegistry.addSvgIcon('logo', sanitizer.bypassSecurityTrustResourceUrl('assets/icons/logo.svg'));
}
ngOnInit() {
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
if (width < 768) {
if(width < 768) {
this.opened = false;
} else {
this.opened = true;
@ -45,13 +48,15 @@ export class AppComponent {
logout() {
this.authService.logout().subscribe(data => {
this.router.navigate([""]);
this.router.navigate([""]).then(() => {
window.location.reload();
});
})
}
isBiggerScreen() {
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
if (width < 768) {
if(width < 768) {
return false;
} else {
return true;
@ -60,7 +65,7 @@ export class AppComponent {
@HostListener('window:resize', ['$event'])
onResize(event) {
if (event.target.innerWidth < 768) {
if(event.target.innerWidth < 768) {
this.opened = false;
} else {
this.opened = true;

View File

@ -1,47 +1,49 @@
import { NgModule, Injectable, APP_INITIALIZER } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule, HttpInterceptor, HttpHandler, HttpRequest, HTTP_INTERCEPTORS } from '@angular/common/http';
import { MaterialModule } from './material/material.module';
import { QRCodeModule } from 'angularx-qrcode';
import {NgModule, Injectable, APP_INITIALIZER} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {AppRoutingModule} from './app-routing.module';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {HttpClientModule, HttpInterceptor, HttpHandler, HttpRequest, HTTP_INTERCEPTORS} from '@angular/common/http';
import {MaterialModule} from './material/material.module';
import {QRCodeModule} from 'angularx-qrcode';
import { I18nPipe } from './utils/i18n.pipe';
import { HomeComponent, ImprintComponent, PrivacyPolicyComponent } from './pages/home/home.component';
import { HomeClubComponent } from './pages/home/club/home-club.component';
import { HomeGeneralComponent } from './pages/home/general/home-general.component';
import { HomePrivacyComponent } from './pages/home/privacy/home-privacy.component';
import { HomeServicesComponent } from './pages/home/services/home-services.component';
import { AccountComponent } from './pages/account/account.component';
import { AppsComponent } from './pages/apps/apps.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 { TokensComponent } from './pages/tokens/tokens.component';
import { PermissionsComponent } from './ui/permissions/permissions.component';
import { QuotasComponent } from './ui/quotas/quotas.component';
import { SecurityComponent, SecurityTotpDialog } from './pages/account/security/security.component';
import { VoucherComponent } from './pages/account/voucher/voucher.component';
import { VoucherDialog } from './pages/account/voucher/voucher.component';
import { InfoComponent } from './pages/account/info/info.component';
import { PasswordComponent } from './pages/password/password.component';
import { PasswordResetComponent } from './pages/password-reset/password-reset.component';
import { RegisterComponent, RegisterDialog } from './pages/register/register.component';
import { UsernameDialog } from './pages/register/username-dialog/username.dialog';
import { UnavailableComponent } from './pages/unavailable/unavailable.component';
import { NotfoundComponent } from './pages/notfound/notfound.component';
import { HtmlComponent } from './utils/html/html.component';
import {I18nPipe} from './utils/i18n.pipe';
import {HomeComponent, ImprintComponent, PrivacyPolicyComponent, TermsOfServiceComponent} from './pages/home/home.component';
import {HomeClubComponent} from './pages/home/club/home-club.component';
import {HomeGeneralComponent} from './pages/home/general/home-general.component';
import {HomePrivacyComponent} from './pages/home/privacy/home-privacy.component';
import {HomeServicesComponent} from './pages/home/services/home-services.component';
import {AccountComponent} from './pages/account/account.component';
import {AppsComponent} from './pages/apps/apps.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 {TokensComponent} from './pages/tokens/tokens.component';
import {PermissionsComponent} from './ui/permissions/permissions.component';
import {ProfileFieldDialog, ProfileFieldsComponent, ProfileFieldBlob} from './ui/profilefields/profilefields.component';
import {QuotasComponent} from './ui/quotas/quotas.component';
import {SecurityComponent, SecurityTotpDialog} from './pages/account/security/security.component';
import {VoucherComponent} from './pages/account/voucher/voucher.component';
import {VoucherDialog} from './pages/account/voucher/voucher.component';
import {InfoComponent} from './pages/account/info/info.component';
import {ProfileComponent} from './pages/account/profile/profile.component';
import {PasswordComponent} from './pages/password/password.component';
import {PasswordResetComponent} from './pages/password-reset/password-reset.component';
import {RegisterComponent, RegisterDialog} from './pages/register/register.component';
import {UsernameDialog} from './pages/register/username-dialog/username.dialog';
import {UnavailableComponent} from './pages/unavailable/unavailable.component';
import {NotfoundComponent} from './pages/notfound/notfound.component';
import {HtmlComponent} from './utils/html/html.component';
import { I18nService } from './services/i18n.service';
import {I18nService} from './services/i18n.service';
export function init_app(i18n: I18nService) {
return () => i18n.fetch(i18n.getLocale()).then(response => { }, error => { });
return () => i18n.fetch(i18n.getLocale()).then(response => {}, error => {});
}
@Injectable()
@ -59,7 +61,7 @@ export class XhrInterceptor implements HttpInterceptor {
declarations: [
I18nPipe,
AppComponent,
HomeComponent, ImprintComponent, PrivacyPolicyComponent,
HomeComponent, ImprintComponent, PrivacyPolicyComponent, TermsOfServiceComponent,
HomeClubComponent,
HomeGeneralComponent,
HomePrivacyComponent,
@ -72,12 +74,14 @@ export class XhrInterceptor implements HttpInterceptor {
TokensComponent,
AppsComponent,
PermissionsComponent,
ProfileFieldsComponent, ProfileFieldDialog, ProfileFieldBlob,
QuotasComponent,
SecurityComponent,
SecurityTotpDialog,
VoucherComponent,
VoucherDialog,
InfoComponent,
ProfileComponent,
PasswordComponent,
PasswordResetComponent,
RegisterComponent,
@ -98,7 +102,7 @@ export class XhrInterceptor implements HttpInterceptor {
QRCodeModule,
],
exports: [MaterialModule],
providers: [{ provide: APP_INITIALIZER, useFactory: init_app, deps: [I18nService], multi: true }, { provide: HTTP_INTERCEPTORS, useClass: XhrInterceptor, multi: true }],
providers: [{provide: APP_INITIALIZER, useFactory: init_app, deps: [I18nService], multi: true}, {provide: HTTP_INTERCEPTORS, useClass: XhrInterceptor, multi: true}],
bootstrap: [AppComponent],
})
export class AppModule {

View File

@ -42,6 +42,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { MatMomentDateModule } from '@angular/material-moment-adapter';
@NgModule({
declarations: [],
@ -81,7 +82,8 @@ import { MatTableModule } from '@angular/material/table';
MatTooltipModule,
MatPaginatorModule,
MatSortModule,
MatTableModule
MatTableModule,
MatMomentDateModule
],
exports: [
MatAutocompleteModule,

View File

@ -3,6 +3,7 @@
<nav mat-tab-nav-bar>
<a mat-tab-link routerLink="info" routerLinkActive="active">{{'info' | i18n}}</a>
<a mat-tab-link routerLink="profile" routerLinkActive="active">{{'profile' | i18n}}</a>
<a mat-tab-link routerLink="voucher" routerLinkActive="active">{{'vouchers' | i18n}}</a>
<a mat-tab-link routerLink="security" routerLinkActive="active">{{'security' | i18n}}</a>
</nav>

View File

@ -2,3 +2,5 @@
<app-permissions [permissions]="permissions"></app-permissions>
<h3>{{'quotas' | i18n}}</h3>
<app-quotas [quotas]="quotas"></app-quotas>
<h3>{{'profile' | i18n}}</h3>
<app-profilefields [profileFields]="profileFields"></app-profilefields>

View File

@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { PermissionService } from './../../../services/permission.service';
import { QuotaService } from './../../../services/quota.service';
import { ProfileService } from './../../../services/profile.service';
@Component({
selector: 'app-account-info',
@ -11,8 +12,9 @@ export class InfoComponent implements OnInit {
permissions = [];
quotas = [];
profileFields = [];
constructor(private permissionService: PermissionService, private quotaService: QuotaService) { }
constructor(private permissionService: PermissionService, private quotaService: QuotaService, private profileService : ProfileService) { }
ngOnInit(): void {
this.permissionService.permissions().subscribe((data: any) => {
@ -22,6 +24,10 @@ export class InfoComponent implements OnInit {
this.quotaService.quotas().subscribe((data: any) => {
this.quotas = data;
})
this.profileService.getAll().subscribe((data: any) => {
this.profileFields = data;
})
}
}

View File

@ -0,0 +1 @@
<app-profilefields [profileFields]="profileFields" [edit]="true"></app-profilefields>

View File

@ -0,0 +1,8 @@
table {
width: 100%;
}
td.mat-cell {
padding: 12px;
}

View File

@ -0,0 +1,25 @@
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();
});
});

View File

@ -0,0 +1,24 @@
import {Component, OnInit} from '@angular/core';
import {ProfileService} from '../../../services/profile.service';
import {I18nService} from '../../../services/i18n.service';
@Component({
selector: 'app-account-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.scss']
})
export class ProfileComponent implements OnInit {
profileFields = [];
types = ["TEXT", "NUMBER", "DATE", "URL", "EMAIL", "BOOL"];
visibilities = ["PRIVATE", "PROTECTED", "PUBLIC"];
constructor(private profileService: ProfileService, private i18n: I18nService) {}
ngOnInit(): void {
this.profileService.getAll().subscribe((data: any) => {
this.profileFields = data;
})
}
}

View File

@ -12,5 +12,5 @@
</div>
<div mat-dialog-actions>
<button mat-button [mat-dialog-close]="false">{{'cancel' | i18n}}</button>
<button [disabled]="code.invalid" mat-raised-button [mat-dialog-close]="code.value" cdkFocusInitial color="accent">{{'security.2fa.totp.enable' | i18n}}</button>
<button [disabled]="code.invalid" mat-raised-button [mat-dialog-close]="code.value" color="accent">{{'security.2fa.totp.enable' | i18n}}</button>
</div>

View File

@ -23,7 +23,7 @@
{{'home.club.charter' | i18n}}
</mat-panel-title>
</mat-expansion-panel-header>
<app-html [template]="'club/charter'"></app-html>
<app-html class="text-justify" [template]="'club/charter'"></app-html>
</mat-expansion-panel>
</mat-accordion>

View File

@ -42,3 +42,17 @@ export class PrivacyPolicyComponent implements OnInit {
}
}
@Component({
selector: 'app-terms-of-service',
templateUrl: './home.terms-of-service.html'
})
export class TermsOfServiceComponent implements OnInit {
constructor() {
}
ngOnInit(): void {
}
}

View File

@ -0,0 +1 @@
<app-html [template]="'terms-of-service'"></app-html>

View File

@ -1,15 +1,15 @@
import { Component, OnInit, Inject } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { Router } from '@angular/router';
import {Component, OnInit, Inject, ViewChild, ElementRef} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import {Router} from '@angular/router';
import { UserService } from './../../services/user.service';
import { ItemService } from './../../services/item.service';
import { I18nService } from './../../services/i18n.service';
import { MatchingValidator } from './../../utils/matching.validator';
import {UserService} from './../../services/user.service';
import {ItemService} from './../../services/item.service';
import {I18nService} from './../../services/i18n.service';
import {MatchingValidator} from './../../utils/matching.validator';
import { uniqueNamesGenerator, Config, adjectives, colors, animals } from 'unique-names-generator';
import {uniqueNamesGenerator, Config, adjectives, colors, animals} from 'unique-names-generator';
var openpgp = require('openpgp');
@ -71,10 +71,10 @@ export class RegisterComponent implements OnInit {
register() {
this.missingToken = false;
if (this.form.valid && !this.working) {
if(this.form.valid && !this.working) {
this.working = true;
let pgpOption = {
userIds: [{ name: this.model.username, email: this.model.username + "@we.bstly.de" }],
userIds: [{name: this.model.username, email: this.model.username + "@we.bstly.de"}],
curve: "ed25519",
}
@ -82,18 +82,21 @@ export class RegisterComponent implements OnInit {
openpgp.generateKey(pgpOption).then((key) => {
privKey = key.privateKeyArmored;
pubKey = key.publicKeyArmored;
this.model.publicKey = pubKey;
this.model.profileFields = [
{"name": "publicKey", "type": "BLOB", "visibility": "PROTECTED", "blob": pubKey}
]
if(this.model.email) {
this.model.profileFields.push({"name": "email", "type": "EMAIL", "visibility": "PRITAVE", "value": this.model.email})
}
if(this.model.primaryEmail) {
this.model.profileFields.push({"name": "primaryEmail", "type": "BOOL", "visibility": "PRITAVE", "value": this.model.primaryEmail})
}
this.userService.register(this.model).subscribe((result: any) => {
result.privateKey = privKey;
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(privKey));
element.setAttribute('download', result.username + ".private.key");
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
const dialogRef = this.dialog.open(RegisterDialog, {
closeOnNavigation: false,
disableClose: true,
@ -101,7 +104,7 @@ export class RegisterComponent implements OnInit {
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
if(result) {
this.success = true;
}
});
@ -109,20 +112,21 @@ export class RegisterComponent implements OnInit {
this.working = false;
}, (error) => {
this.working = false;
if (error.status == 401) {
if(error.status == 401) {
this.missingToken = true;
} else if (error.status == 409) {
} else if(error.status == 409) {
let errors = {};
for (let code of error.error) {
for(let code of error.error) {
errors[code.field] = errors[code.field] || {};
errors[code.field][code.code] = true;
}
for (let code in errors) {
for(let code in errors) {
this.form.get(code).setErrors(errors[code]);
}
}
})
})
}
}
@ -136,8 +140,22 @@ export class RegisterComponent implements OnInit {
})
export class RegisterDialog {
public downloaded: boolean = false;
@ViewChild("downloadKey", {read: ElementRef}) downloadKey: ElementRef;
constructor(private router: Router,
public dialogRef: MatDialogRef<RegisterDialog>,
@Inject(MAT_DIALOG_DATA) public data: any) { }
@Inject(MAT_DIALOG_DATA) public data: any) {
}
ngAfterViewInit() {
this.downloadKey.nativeElement.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(this.data.privateKey));
this.downloadKey.nativeElement.setAttribute('download', this.data.username + ".private.key");
}
setDownloaded() {
this.downloaded = true;
}
}

View File

@ -1,5 +1,5 @@
<h1 mat-dialog-title>{{data.username}}</h1>
<div mat-dialog-content>
<mat-dialog-content>
<h3>{{'permissions' | i18n}}</h3>
<app-permissions [permissions]="data.permissions"></app-permissions>
<h3>{{'quotas' | i18n}}</h3>
@ -10,11 +10,19 @@
<mat-label>{{'pgp.privateKey' | i18n}}</mat-label>
<textarea matInput readonly [(ngModel)]="data.privateKey"></textarea>
</mat-form-field>
</div>
<div mat-dialog-actions>
<mat-slide-toggle [(ngModel)]="data.confirmClose">
</mat-dialog-content>
<mat-dialog-actions>
<a mat-raised-button color="primary" #downloadKey (click)="setDownloaded()">{{'pgp.privateKey.downloadKey' |
i18n}}</a>
<button mat-icon-button [matTooltip]="'pgp.privateKey.help' | i18n" matTooltipPosition="after">
<mat-icon>help</mat-icon>
</button>
</mat-dialog-actions>
<br />
<mat-dialog-actions>
<mat-slide-toggle [(ngModel)]="data.confirmClose" [disabled]="!downloaded">
{{'pgp.privateKey.confirmStore' | i18n}}
</mat-slide-toggle>
<button mat-button [disabled]="!data.confirmClose" [mat-dialog-close]="true">{{'ok' | i18n}}</button>
</div>
</mat-dialog-actions>

View File

@ -0,0 +1,33 @@
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {environment} from '../../environments/environment';
@Injectable({
providedIn: 'root',
})
export class ProfileService {
constructor(private http: HttpClient) {
}
getAll() {
return this.http.get(environment.apiUrl + "/profiles");
}
getAllForUser(username) {
return this.http.get(environment.apiUrl + "/profiles/" + username);
}
getForUser(username, name) {
return this.http.get(environment.apiUrl + "/profiles/" + username + "/" + name);
}
createOrUpdate(profileModel) {
return this.http.post(environment.apiUrl + "/profiles", profileModel);
}
delete(name) {
return this.http.delete(environment.apiUrl + "/profiles/" + name);
}
}

View File

@ -6,9 +6,14 @@
</td>
</ng-container>
<ng-container matColumnDef="starts">
<th mat-header-cell *matHeaderCellDef mat-sort-header="starts"> {{'permissions.starts' | i18n}} </th>
<td mat-cell *matCellDef="let permission">{{permission.starts | date:datetimeformat}}</td>
</ng-container>
<ng-container matColumnDef="expires">
<th mat-header-cell *matHeaderCellDef mat-sort-header="expires"> {{'permissions.expires' | i18n}} </th>
<td mat-cell *matCellDef="let permission">{{permission.expires | date}}</td>
<td mat-cell *matCellDef="let permission">{{permission.expires | date:datetimeformat}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="permissionColumns"></tr>

View File

@ -9,13 +9,14 @@ import { I18nService } from './../../services/i18n.service';
})
export class PermissionsComponent implements OnInit {
datetimeformat: String;
@Input() permissions;
permissionColumns = ["name", "expires"];
permissionColumns = ["name", "starts", "expires"];
constructor(private i18n: I18nService) { }
ngOnInit(): void {
this.datetimeformat = this.i18n.get('date-time-format',[]);
}
sortData(sort: Sort) {
@ -28,7 +29,8 @@ export class PermissionsComponent implements OnInit {
this.permissions = data.sort((a, b) => {
const isAsc = sort.direction === 'asc';
switch (sort.active) {
case 'name': return this.compare(this.i18n.get('permissions.' + a.name,[]), this.i18n.get('permissions.' + b.name,[]), isAsc);
case 'name': return this.compare(this.i18n.get('permissions.' + a.name, []), this.i18n.get('permissions.' + b.name, []), isAsc);
case 'starts': return this.compare(a.starts, b.starts, isAsc);
case 'expires': return this.compare(a.expires, b.expires, isAsc);
default: return 0;
}

View File

@ -0,0 +1,9 @@
<h1 mat-dialog-title></h1>
<mat-dialog-content>
<pre>
{{profileField.blob}}
</pre>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button mat-dialog-close>{{'close' | i18n}}</button>
</mat-dialog-actions>

View File

@ -0,0 +1,3 @@
mat-form-field {
display: block;
}

View File

@ -0,0 +1,66 @@
<h1 mat-dialog-title></h1>
<mat-dialog-content>
<form [formGroup]="form">
<mat-form-field>
<input matInput type="text" min="3" [(ngModel)]="profileField.name" formControlName="name"
placeholder="{{'profileField.name' | i18n}}">
</mat-form-field>
<mat-form-field>
<mat-select [(ngModel)]="profileField.type" formControlName="type" placeholder="{{'profileField.type' | i18n}}">
<mat-option *ngFor="let type of types" [value]="type">
{{'profileField.type.' + type | i18n}}
</mat-option>
</mat-select>
</mat-form-field>
<div [ngSwitch]="profileField.type">
<mat-form-field *ngSwitchCase="'TEXT'">
<input matInput type="text" max="255" [(ngModel)]="profileField.value" formControlName="value"
placeholder="{{'profileField.value' | i18n}}">
</mat-form-field>
<mat-form-field *ngSwitchCase="'DATE'">
<input matInput [matDatepicker]="picker" [(ngModel)]="profileField.value" formControlName="value"
placeholder="{{'profileField.value' | i18n}}">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<mat-form-field *ngSwitchCase="'URL'">
<input matInput type="url" [(ngModel)]="profileField.value" formControlName="value"
placeholder="{{'profileField.value' | i18n}}">
</mat-form-field>
<mat-form-field *ngSwitchCase="'EMAIL'">
<input matInput type="email" [(ngModel)]="profileField.value" formControlName="value"
placeholder="{{'profileField.value' | i18n}}">
</mat-form-field>
<mat-form-field *ngSwitchCase="'NUMBER'">
<input matInput type="number" [(ngModel)]="profileField.value" formControlName="value"
placeholder="{{'profileField.value' | i18n}}">
</mat-form-field>
<mat-form-field *ngSwitchCase="'BLOB'">
<textarea matInput [(ngModel)]="profileField.blob" formControlName="blob"
placeholder="{{'profileField.value' | i18n}}"></textarea>
</mat-form-field>
</div>
<mat-form-field>
<mat-select [(ngModel)]="profileField.visibility" formControlName="visibility"
placeholder="{{'profileField.visibility' | i18n}}">
<mat-option *ngFor="let visibility of visibilities" [value]="visibility">
{{'profileField.visibility.' + visibility | i18n}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<input matInput type="number" min="0" [(ngModel)]="profileField.index" formControlName="index"
placeholder="{{'profileField.index' | i18n}}">
</mat-form-field>
</form>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button [mat-dialog-close]="false">{{'cancel' | i18n}}</button>
<button [disabled]="form.invalid" mat-raised-button [mat-dialog-close]="profileField" color="accent">{{'save' | i18n}}</button>
</mat-dialog-actions>

View File

@ -0,0 +1,3 @@
mat-form-field {
display: block;
}

View File

@ -0,0 +1,55 @@
<table mat-table matSort [dataSource]="profileFields" (matSortChange)="sortData($event)" matSortActive="index"
matSortDirection="asc">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'profileField.name' | i18n}} </th>
<td mat-cell *matCellDef="let profileField"> {{'profileField.name.' + profileField.name | i18n}} </td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef mat-sort-header="value"> {{'profileField.value' | i18n}} </th>
<td mat-cell *matCellDef="let profileField">
<div [ngSwitch]="profileField.type">
<span *ngSwitchCase="'TEXT'">{{profileField.value}}</span>
<span *ngSwitchCase="'DATE'">{{profileField.value | date:datetimeformat}}</span>
<a *ngSwitchCase="'URL'" href="{{profileField.value}}">{{profileField.value}}</a>
<a *ngSwitchCase="'EMAIL'" href="mailto:{{profileField.value}}">{{profileField.value}}</a>
<span *ngSwitchCase="'NUMBER'">{{profileField.value}}</span>
<button *ngSwitchCase="'BLOB'" mat-raised-button
(click)="openBlob(profileField)">{{'profileField.openBlob' | i18n}}</button>
</div>
</td>
</ng-container>
<ng-container matColumnDef="visibility" *ngIf="edit">
<th mat-header-cell *matHeaderCellDef mat-sort-header="visibility"> {{'profileField.visibility' | i18n}} </th>
<td mat-cell *matCellDef="let profileField"> {{'profileField.visibility.' + profileField.visibility | i18n}}
</td>
</ng-container>
<ng-container matColumnDef="edit" *ngIf="edit">
<th mat-header-cell *matHeaderCellDef> {{'profileField.edit' | i18n}} </th>
<td mat-cell *matCellDef="let profileField">
<a mat-icon-button>
<mat-icon (click)="openEdit(profileField)">edit</mat-icon>
</a>
</td>
</ng-container>
<ng-container matColumnDef="delete" *ngIf="edit">
<th mat-header-cell *matHeaderCellDef> {{'profileField.delete' | i18n}} </th>
<td mat-cell *matCellDef="let profileField">
<a mat-icon-button>
<mat-icon (click)="confirmDelete(profileField)">delete</mat-icon>
</a>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="profileFieldColumns"></tr>
<tr mat-row *matRowDef="let myRowData; columns: profileFieldColumns"></tr>
</table>
<br>
<div *ngIf="edit" class="text-center">
<button mat-raised-button color="primary" (click)="openCreate()">{{'profileField.create' |
i18n}}</button>
</div>

View File

@ -0,0 +1,3 @@
table {
width: 100%;
}

View File

@ -0,0 +1,25 @@
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();
});
});

View File

@ -0,0 +1,159 @@
import {Component, OnInit, Inject, Input} from '@angular/core';
import {Sort} from '@angular/material/sort';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import {I18nService} from '../../services/i18n.service';
import {ProfileService} from '../../services/profile.service';
@Component({
selector: 'app-profilefields',
templateUrl: './profilefields.component.html',
styleUrls: ['./profilefields.component.scss']
})
export class ProfileFieldsComponent implements OnInit {
@Input() profileFields: Array<any>;
@Input() edit;
profileFieldColumns = ["name", "value"];
constructor(private i18n: I18nService, private profileService: ProfileService, public dialog: MatDialog) {}
ngOnInit(): void {
if(this.edit) {
this.profileFieldColumns.push("visibility");
this.profileFieldColumns.push("edit");
this.profileFieldColumns.push("delete");
}
}
sortData(sort: Sort) {
const data = this.profileFields.slice();
if(!sort.active || sort.direction === '') {
this.profileFields = data;
return;
}
this.profileFields = data.sort((a, b) => {
const isAsc = sort.direction === 'asc';
switch(sort.active) {
case 'name': return this.compare(this.i18n.get('profileField.name.' + a.name, []), this.i18n.get('profileField.name.' + b.name, []), isAsc);
case 'value': return this.compare(a.value, b.value, isAsc);
case 'index': return this.compare(a.index, b.index, isAsc);
default: return 0;
}
});
}
compare(a: number | string | String, b: number | string | String, isAsc: boolean) {
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}
openEdit(profileField) {
const resetProfileField = JSON.parse(JSON.stringify(profileField));
const dialogRef = this.dialog.open(ProfileFieldDialog, {
data: profileField,
minWidth : '400px'
});
dialogRef.afterClosed().subscribe(result => {
if(result) {
this.profileService.createOrUpdate(result).subscribe();
} else {
profileField.name = resetProfileField.name;
profileField.value = resetProfileField.value;
profileField.type = resetProfileField.type;
profileField.visibility = resetProfileField.visibility;
profileField.index = resetProfileField.index;
}
});
}
confirmDelete(profileField) {
this.profileService.delete(profileField.name).subscribe((result: any) => {
this.profileFields.splice(this.profileFields.indexOf(profileField), 1);
this.profileFields = [...this.profileFields];
})
}
openCreate() {
const dialogRef = this.dialog.open(ProfileFieldDialog, {
data: {"type": "TEXT", "visibility": "PRIVATE"},
minWidth : '400px'
});
dialogRef.afterClosed().subscribe(result => {
if(result) {
this.profileService.createOrUpdate(result).subscribe((result: any) => {
this.profileFields.push(result);
this.profileFields = [...this.profileFields];
});
}
});
}
openBlob(profileField) {
this.dialog.open(ProfileFieldBlob, {
data: profileField,
minWidth : '400px'
});
}
}
@Component({
selector: 'app-profilefield-dialog',
templateUrl: 'profilefield.dialog.html',
styleUrls: ['./profilefield.dialog.scss']
})
export class ProfileFieldDialog {
form: FormGroup;
profileField;
types = ["TEXT", "NUMBER", "DATE", "URL", "EMAIL", "BOOL", "BLOB"];
visibilities = ["PRIVATE", "PROTECTED", "PUBLIC"];
constructor(
private formBuilder: FormBuilder,
public dialogRef: MatDialogRef<ProfileFieldDialog>,
@Inject(MAT_DIALOG_DATA) public data: any) {
this.profileField = data;
}
ngOnInit() {
this.form = this.formBuilder.group({
name: ['', Validators.required],
type: ['', Validators.required],
value: [''],
blob: [''],
visibility: ['', Validators.required],
index: ['']
});
}
}
@Component({
selector: 'app-profilefield-blob',
templateUrl: 'profilefield.blob.html',
styleUrls: ['./profilefield.blob.scss']
})
export class ProfileFieldBlob {
profileField;
constructor(
public dialogRef: MatDialogRef<ProfileFieldDialog>,
@Inject(MAT_DIALOG_DATA) public data: any) {
this.profileField = data;
}
}

View File

@ -1,5 +1,6 @@
{
"i18n.test.replace": "Wat!?! {0} {1} {2}",
"date-time-format": "dd.MM.yyyy HH:mm:ss",
"greet": "Hallo {0}",
"home": {
".": "Über we.bstly",
@ -55,6 +56,8 @@
"account": "Account",
"token": "Token",
"ok": "Ok",
"save": "Speichern",
"close" : "Schliessen",
"tokens": {
".": "Tokens",
"redeem": "Tokens einlösen",
@ -145,6 +148,7 @@
"permissions": {
".": "Berechtigungen",
"name": "Name",
"starts": "Gültig ab",
"expires": "Gültig bis",
"nextcloud": "Nextcloud",
"mail": "E-Mail Postfach",
@ -207,6 +211,7 @@
".": "PGP",
"privateKey": {
".": "Privater PGP Schlüssel",
"downloadKey": "Privaten Schlüssel herunterladen",
"confirmStore": "Ich habe meinen privaten Schlüssel sicher gespeichert!"
}
},
@ -214,5 +219,51 @@
"sourcecode": "Quellcode",
"homepage": "Homepage",
"imprint": "Impressum",
"privacy-policy": "Datenschutzerklärung"
"privacy-policy": "Datenschutzerklärung",
"profile": "Profil",
"profileField": {
".": "Profilfeld",
"name": {
".": "Name"
},
"type": {
".": "Typ",
"TEXT": {
".": "Textfeld"
},
"NUMBER": {
".": "Numerisch"
},
"DATE": {
".": "Datum"
},
"URL": {
".": "URL"
},
"EMAIL": {
".": "E-Mail"
},
"BOOL": {
".": "Boolean"
}
},
"edit": "Bearbeiten",
"delete": "Löschen",
"openBlob" : "Anzeigen",
"create": "Neues Profilfeld hinzufügen",
"value": "Wert",
"index": "Index",
"visibility": {
".": "Sichtbarkeit",
"PRIVATE": {
".": "Privat"
},
"PROTECTED": {
".": "Geschützt"
},
"PUBLIC": {
".": "Öffentlich"
}
}
}
}

View File

@ -1,5 +1,6 @@
{
"i18n.test.replace": "yes no it's clear! {0} {1} {2}",
"date-time-format": "yyyy/dd/MM HH:mm:ss",
"greet": "Hello {0}",
"home": "Home",
"cancel" : "Cancel",
@ -129,5 +130,49 @@
},
"software" : "Software",
"sourcecode": "Sourcecode",
"homepage": "Homepage"
"homepage": "Homepage",
"profile": "Profile",
"imprint": "Imprint",
"privacy-policy": "Privacy-Policy",
"profileField": {
".": "Profilefield",
"name": {
".": "Name"
},
"type": {
".": "Typ",
"TEXT": {
".": "Textfield"
},
"NUMBER": {
".": "Numeric"
},
"DATE": {
".": "Date"
},
"URL": {
".": "URL"
},
"EMAIL": {
".": "Email"
},
"BOOL": {
".": "Boolean"
}
},
"value": "Value",
"index": "Index",
"visibility": {
".": "Visibility",
"PRIVATE": {
".": "Private"
},
"PROTECTED": {
".": "Protected"
},
"PUBLIC": {
".": "Public"
}
}
}
}

View File

@ -1,2 +1,2 @@
<h2>we.bstly</h2>
<p>Willkommen zu 'Bastelei (bald e.V.)'.</p>
<p>Willkommen zu 'Bastelei e. V.'.</p>

View File

@ -1,5 +1,5 @@
<h1>Satzung</h1>
<p>des “Bastelei e.V.”</p>
<p>des “Bastelei e. V.”</p>
<h3>Präambel</h3>
@ -40,10 +40,8 @@
Zahlung des ersten Beitrages im Voraus. Die Vorläufigkeit endet mit der Bestätigung des Mitglieds durch den
Vorstand.</p>
<p>Die Mitgliedschaft endet durch Austrittserklärung, durch Tod von natürlichen Personen oder durch Auflösung und
Erlöschen von juristischen Personen, Handelsgesellschaften, nicht rechtsfähigen Vereinen sowie Anstalten und
Körperschaften des öffentlichen Rechts oder durch Ausschluss; die Beitragspflicht für das laufende Beitragsjahr
bleibt hiervon unberührt.</p>
<p>Die Mitgliedschaft endet durch Austrittserklärung, durch Tod von natürlichen Personen oder durch Ausschluss; die
Beitragspflicht für das laufende Beitragsjahr bleibt hiervon unberührt.</p>
<p>Der Austritt wird durch Willenserklärung in Textform gegenüber dem Vorstand vollzogen.</p>
@ -56,7 +54,8 @@
erforderlich.</p>
<h2>§4 Rechte und Pflichten der Mitglieder</h2>
<p>Die Mitglieder sind berechtigt, die Leistungen des Vereins in Anspruch zu nehmen.</p>
<p>Die Mitglieder sind berechtigt, die Einrichtungen des Vereins in Anspruch zu nehmen und an Veranstaltungen des
Vereins teilzunehmen.</p>
<p>Die Mitglieder sind verpflichtet, die satzungsgemäßen Zwecke des Vereins zu unterstützen und zu fördern. Sie sind
verpflichtet, die festgesetzten Beiträge zu zahlen.</p>
@ -108,24 +107,22 @@
<p>Mitgliederversammlungen können digital oder auch als Hybridveranstaltungen abgehalten werden. Technische
Hürden können durch Bildung von Kleingruppen gelöst werden.</p>
<p>Außerordentliche Mitgliederversammlungen werden auf Beschluss des Vorstandes abgehalten, wenn die Interessen des
<p> Außerordentliche Mitgliederversammlungen werden auf Beschluss des Vorstandes abgehalten, wenn die Interessen des
Vereins dies erfordern, oder wenn mindestens fünf Prozent, bei weniger als 60 Mitgliedern mindestens drei
Mitglieder, aller stimmberechtigten Mitglieder dies unter Angabe des Zwecks in Textform beantragen. Die Einberufung
der Mitgliederversammlung erfolgt in Textform durch den Vorstand mit einer Frist von mindestens zwei Wochen. Zur
Wahrung der Frist reicht die Versendung an die zuletzt bekannte E-Mail-Adresse oder die Aufgabe der Einladung zur
Post an die letzte bekannte Anschrift. Hierbei sind die Tagesordnung bekannt zugeben und ihr die nötigen
Informationen zugänglich zu machen. Anträge zur Tagesordnung sind mindestens sieben Tage vor der
Mitgliederversammlung beim Vorstand in Textform einzureichen. Über die Behandlung von Initiativanträgen entscheidet
die Mitgliederversammlung.
</p>
Mitglieder, aller stimmberechtigten Mitglieder dies unter Angabe des Zwecks in Textform beantragen.</p>
<p>Die Einberufung der Mitgliederversammlung erfolgt in Textform durch den Vorstand mit einer Frist von mindestens zwei
Wochen. Eine verkürzte Frist ist möglich, wenn alle Mitglieder der Frist vor Ablauf zustimmen. Zur Wahrung der Frist
reicht die Versendung an die zuletzt bekannte E-Mail-Adresse oder die Aufgabe der Einladung zur Post an die letzte
bekannte Anschrift. Hierbei sind die Tagesordnung bekannt zu geben und ihr die nötigen Informationen zugänglich zu
machen. Anträge zur Tagesordnung sind mindestens sieben Tage vor der Mitgliederversammlung beim Vorstand in Textform
einzureichen. Über die Behandlung von Initiativanträgen entscheidet die Mitgliederversammlung.</p>
<p>Die Mitgliederversammlung ist beschlussfähig, wenn mindestens fünf Prozent, bei weniger als 60 Mitgliedern mindestens
drei Mitglieder, aller stimmberechtigten Mitglieder anwesend sind. Beschlüsse sind jedoch gültig, wenn die
Beschlussfähigkeit vor der
Beschlussfassung nicht angezweifelt worden ist. Ist die Mitgliederversammlung aufgrund mangelnder Teilnehmerzahl
nicht
beschlussfähig, ist die darauf folgende ordentlich einberufene Mitgliederversammlung ungeachtet der Teilnehmerzahl
beschlussfähig.</p>
Beschlussfähigkeit vor der Beschlussfassung nicht angezweifelt worden ist. Ist die Mitgliederversammlung aufgrund
mangelnder Teilnehmerzahl nicht beschlussfähig, ist die darauf folgende ordentlich einberufene Mitgliederversammlung
ungeachtet der Teilnehmerzahl beschlussfähig. Auf Letzteres muss in der Einladung hingewiesen werden.</p>
<p>Beschlüsse über Satzungsänderungen und über die Auflösung des Vereins bedürfen zu ihrer Rechtswirksamkeit
der Dreiviertelmehrheit der anwesenden stimmberechtigten Mitglieder. In allen anderen Fällen genügt die
@ -145,22 +142,20 @@
durchgeführt werden. Abwesende Mitglieder können so jedoch auch an Wahlen teilnehmen. Technische Hürden
können durch Bevollmächtigungen gelöst werden.</p>
<p>Jede WählerIn kann beliebig vielen KandidatInnen jeweils eine Stimme geben. Jeder zu besetzende Posten
wird einzeln gewählt, wobei gleichrangige Posten (die zwei FinanzprüferInnen) jeweils gemeinsam gewählt
werden können. Bei der Wahl des Vorstandes ist gewählt, wer die meisten abgegebenen Stimmen erhält. Bei
Stimmengleichheit findet eine Stichwahl statt. Bei erneuter Stimmengleichheit entscheidet das Los. Bei
der Wahl der FinanzprüferInnen sind diejenigen beiden KandidatInnen gewählt, die die meisten Stimmen erhalten.
Bei Stimmengleichheit findet eine Stichwahl statt. Bei erneuter Stimmengleichheit entscheidet das Los.
<p>Jeder zu besetzende Posten wird einzeln gewählt, wobei gleichrangige Posten jeweils gemeinsam gewählt werden können.
Bei der Wahl des Vorstandes ist gewählt, wer die meisten abgegebenen Stimmen erhält. Bei Stimmengleichheit findet
eine Stichwahl statt. Bei erneuter Stimmengleichheit entscheidet das Los. Bei der Wahl der FinanzprüferInnen sind
diejenigen beiden KandidatInnen gewählt, die die meisten Stimmen erhalten. Bei Stimmengleichheit findet eine
Stichwahl statt. Bei erneuter Stimmengleichheit entscheidet das Los.
</p>
<h2>§9 Vorstand</h2>
<p>Der Vorstand besteht aus zwei oder mehr gleichberechtigten Mitgliedern.</p>
<p>Der Vorstand im Sinne des §26, Abs. 2 BGB besteht aus zwei oder mehr gleichberechtigten Mitgliedern.</p>
<p>Vorstand im Sinne des § 26, Abs. 2 BGB ist jedes Vorstandsmitglied. Ausgenommen sind Einstellung und
Entlassung von Angestellten, gerichtliche Vertretung sowie Anzeigen, Aufnahme von Krediten, Gründung,
Erwerb und Veräußerung von Gesellschaften und Geschäftsanteilen von Gesellschaften zur Verwirklichung
der satzungsgemäßen Ziele; bei denen der Verein durch mindestens zwei Vorstandsmitglieder vertreten
wird.</p>
<p>Vertretungsberechtigt ist jedes Vorstandsmitglied allein. Ausgenommen sind Einstellung und Entlassung von
Angestellten, gerichtliche Vertretung sowie Anzeigen, Aufnahme von Krediten, Gründung, Erwerb und Veräußerung von
Gesellschaften und Geschäftsanteilen von Gesellschaften zur Verwirklichung der satzungsgemäßen Ziele; bei denen der
Verein durch mindestens zwei Vorstandsmitglieder vertreten wird.</p>
<p>Scheidet ein Vorstandsmitglied vorzeitig aus, kann der Vorstand ein neues Vorstandsmitglied aus dem Kreis der
Mitglieder bis zur nächsten Vollversammlung berufen.</p>
@ -173,7 +168,7 @@
<p>Die Vorstandsmitglieder nehmen eine interne Aufgabenverteilung vor. Mit dem Ablauf des Geschäftsjahres
stellt der Vorstand unverzüglich die Abrechnung sowie die Vermögensübersicht und sonstige Unterlagen von
wirtschaftlichen Belang den FinanzprüferInnen des Vereins zur Prüfung zur Verfügung.</p>
wirtschaftlichem Belang den FinanzprüferInnen des Vereins zur Prüfung zur Verfügung.</p>
<p>Der Vorstand führt die laufenden Geschäfte des Vereins. Bei der Geschäftsführung sind die
Vorstandsmitglieder an die Beschlüsse der Mitgliederversammlung gebunden. Der Vorstand soll seine
@ -182,8 +177,6 @@
<p>Der Vorstand verwaltet das Vereinsvermögen.</p>
<p>Der Verein wird gerichtlich und außergerichtlich durch zwei Vorstandsmitglieder gemeinsam vertreten.</p>
<h2>§10 FinanzprüferInnen</h2>
<p>Zur Kontrolle der Haushaltsführung bestellt die Mitgliederversammlung zwei FinanzprüferInnen. Nach
Durchführung ihrer Prüfung informieren sie den Vorstand von ihrem Prüfungsergebnis und erstatten der

View File

@ -1,7 +1,18 @@
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<h2>Impressum</h2>
<p>Kontakt<br>
Name: Bastelei (bald e. V.)<br>
Name: Bastelei e. V.<br>
Adresse: Asternstraße 6, 58285 Gevelsberg<br>
Telefon: 02332 666 77 01<br>
Fax: 02332 666 76 99<br>
E-Mail: impressum@bstly.de</p>
@ -49,3 +60,6 @@
<p>Wenn du uns mitteilen würdest, dass du trotzdem eine Urheberrechtsverletzung gefunden hast, würden wir das sehr
schätzen. Dann können wir den entsprechenden Inhalt sofort entfernen und würde damit das Urheberrecht nicht mehr
verletzen.</p>
</body>
</html>

View File

@ -1,384 +1,570 @@
<p>Die folgende Erklärung gilt für die Domain bstly.de sowie deren Subdomains.</p>
<h2>Datenschutzerklärung</h2>
<html>
<p>Personenbezogene Daten (nachfolgend zumeist nur „Daten“ genannt) werden von uns nur im Rahmen der Erforderlichkeit
sowie zum Zwecke der Bereitstellung eines funktionsfähigen und nutzerfreundlichen Internetauftritts, inklusive
seiner Inhalte und der dort angebotenen Leistungen, verarbeitet.</p>
<head>
<meta charset="UTF-8" />
</head>
<p>Gemäß Art. 4 Ziffer 1. der Verordnung (EU) 2016/679, also der Datenschutz-Grundverordnung (nachfolgend nur „DSGVO“
genannt), gilt als „Verarbeitung“ jeder mit oder ohne Hilfe automatisierter Verfahren ausgeführter Vorgang oder jede
solche Vorgangsreihe im Zusammenhang mit personenbezogenen Daten, wie das Erheben, das Erfassen, die Organisation,
das Ordnen, die Speicherung, die Anpassung oder Veränderung, das Auslesen, das Abfragen, die Verwendung, die
Offenlegung durch Übermittlung, Verbreitung oder eine andere Form der Bereitstellung, den Abgleich oder die
Verknüpfung, die Einschränkung, das Löschen oder die Vernichtung.</p>
<body>
<p>Die folgende Erklärung gilt für die Domain bstly.de, deren Subdomains sowie für die von Bastelei e. V.
bereitgestellten Services.</p>
<h2>Datenschutzerklärung</h2>
<p>Mit der nachfolgenden Datenschutzerklärung informieren wir dich insbesondere über Art, Umfang, Zweck, Dauer und
Rechtsgrundlage der Verarbeitung personenbezogener Daten, soweit wir entweder allein oder gemeinsam mit anderen über
die Zwecke und Mittel der Verarbeitung entscheiden.</p>
<p>Personenbezogene Daten (nachfolgend zumeist nur „Daten“ genannt) werden von uns nur im Rahmen der
Erforderlichkeit
sowie zum Zwecke der Bereitstellung eines funktionsfähigen und nutzerfreundlichen Internetauftritts, inklusive
seiner Inhalte und der dort angebotenen Leistungen, verarbeitet.</p>
<p>Die Datenschutzerklärung ist wie folgt gegliedert:<br>
I. Informationen über uns als Verantwortliche<br>
II. Rechte der Nutzer und Betroffenen<br>
III. Informationen zur Datenverarbeitung</p>
<p>Gemäß Art. 4 Ziffer 1. der Verordnung (EU) 2016/679, also der Datenschutz-Grundverordnung (nachfolgend nur
„DSGVO“
genannt), gilt als „Verarbeitung“ jeder mit oder ohne Hilfe automatisierter Verfahren ausgeführter Vorgang oder
jede
solche Vorgangsreihe im Zusammenhang mit personenbezogenen Daten, wie das Erheben, das Erfassen, die
Organisation,
das Ordnen, die Speicherung, die Anpassung oder Veränderung, das Auslesen, das Abfragen, die Verwendung, die
Offenlegung durch Übermittlung, Verbreitung oder eine andere Form der Bereitstellung, den Abgleich oder die
Verknüpfung, die Einschränkung, das Löschen oder die Vernichtung.</p>
<p>Mit der nachfolgenden Datenschutzerklärung informieren wir dich insbesondere über Art, Umfang, Zweck, Dauer und
Rechtsgrundlage der Verarbeitung personenbezogener Daten, soweit wir entweder allein oder gemeinsam mit anderen
über
die Zwecke und Mittel der Verarbeitung entscheiden.</p>
<p>Die Datenschutzerklärung ist wie folgt gegliedert:<br>
I. Informationen über uns als Verantwortliche<br>
II. Rechte der Nutzer und Betroffenen<br>
III. Informationen zur Datenverarbeitung</p>
<h3>I. Informationen über uns als Verantwortlicher</h3>
<h3>I. Informationen über uns als Verantwortlicher</h3>
<p>Verantwortliche Anbieter dieses Internetauftritts im datenschutzrechtlichen Sinne:<br>
Name: Bastelei (bald e. V.)<br>
E-Mail: datenschutz@bstly.de</p>
<p>Verantwortliche Anbieter dieses Internetauftritts im datenschutzrechtlichen Sinne:<br>
Name: Bastelei e. V.<br>
Adresse: Asternstraße 6, 58285 Gevelsberg<br>
Telefon: 02332 666 77 01<br>
Fax: 02332 666 76 99<br>
E-Mail: datenschutz@bstly.de</p>
<h3>II. Rechte der Nutzer und Betroffenen</h3>
<h3>II. Rechte der Nutzer und Betroffenen</h3>
<p>Mit Blick auf die nachfolgend noch näher beschriebene Datenverarbeitung hast du als Nutzer und Betroffenen das Recht
auf Bestätigung, ob dich betreffende Daten verarbeitet werden, auf Auskunft über die verarbeiteten Daten, auf
weitere
Informationen über die Datenverarbeitung sowie auf Kopien der Daten (vgl. auch Art. 15 DSGVO);
auf Berichtigung oder Vervollständigung unrichtiger bzw. unvollständiger Daten (vgl. auch Art. 16 DSGVO);
auf unverzügliche Löschung der dich betreffenden Daten (vgl. auch Art. 17 DSGVO), oder, alternativ, soweit eine
weitere Verarbeitung gemäß Art. 17 Abs. 3 DSGVO erforderlich ist, auf Einschränkung der Verarbeitung nach Maßgabe
von Art. 18 DSGVO;
auf Erhalt der dich betreffenden und von dir bereitgestellten Daten und auf Übermittlung dieser Daten an andere
Anbieter/Verantwortliche (vgl. auch Art. 20 DSGVO);<br>
auf Beschwerde gegenüber der Aufsichtsbehörde, sofern du der Ansicht bist, dass die dich betreffenden Daten durch
den Anbieter unter Verstoß gegen datenschutzrechtliche Bestimmungen verarbeitet werden (vgl. auch Art. 77 DSGVO).
</p>
<p>Mit Blick auf die nachfolgend noch näher beschriebene Datenverarbeitung hast du als Nutzer und Betroffenen das
Recht
auf Bestätigung, ob dich betreffende Daten verarbeitet werden, auf Auskunft über die verarbeiteten Daten, auf
weitere
Informationen über die Datenverarbeitung sowie auf Kopien der Daten (vgl. auch Art. 15 DSGVO);
auf Berichtigung oder Vervollständigung unrichtiger bzw. unvollständiger Daten (vgl. auch Art. 16 DSGVO);
auf unverzügliche Löschung der dich betreffenden Daten (vgl. auch Art. 17 DSGVO), oder, alternativ, soweit eine
weitere Verarbeitung gemäß Art. 17 Abs. 3 DSGVO erforderlich ist, auf Einschränkung der Verarbeitung nach
Maßgabe
von Art. 18 DSGVO;
auf Erhalt der dich betreffenden und von dir bereitgestellten Daten und auf Übermittlung dieser Daten an andere
Anbieter/Verantwortliche (vgl. auch Art. 20 DSGVO);<br>
auf Beschwerde gegenüber der Aufsichtsbehörde, sofern du der Ansicht bist, dass die dich betreffenden Daten
durch
den Anbieter unter Verstoß gegen datenschutzrechtliche Bestimmungen verarbeitet werden (vgl. auch Art. 77
DSGVO).
</p>
<p>Darüber hinaus ist der Anbieter dazu verpflichtet, alle Empfänger, denen gegenüber Daten durch den Anbieter
offengelegt worden sind, über jedwede Berichtigung oder Löschung von Daten oder die Einschränkung der Verarbeitung,
die aufgrund der Artikel 16, 17 Abs. 1, 18 DSGVO erfolgt, zu unterrichten. Diese Verpflichtung besteht jedoch nicht,
soweit diese Mitteilung unmöglich oder mit einem unverhältnismäßigen Aufwand verbunden ist. Unbeschadet dessen hat
der Nutzer ein Recht auf Auskunft über diese Empfänger.</p>
<p>Darüber hinaus ist der Anbieter dazu verpflichtet, alle Empfänger, denen gegenüber Daten durch den Anbieter
offengelegt worden sind, über jedwede Berichtigung oder Löschung von Daten oder die Einschränkung der
Verarbeitung,
die aufgrund der Artikel 16, 17 Abs. 1, 18 DSGVO erfolgt, zu unterrichten. Diese Verpflichtung besteht jedoch
nicht,
soweit diese Mitteilung unmöglich oder mit einem unverhältnismäßigen Aufwand verbunden ist. Unbeschadet dessen
hat
der Nutzer ein Recht auf Auskunft über diese Empfänger.</p>
<p>Ebenfalls hast du als Nutzer und Betroffenen nach Art. 21 DSGVO das Recht auf Widerspruch gegen die künftige
Verarbeitung der dich betreffenden Daten, sofern die Daten durch den Anbieter nach Maßgabe von Art. 6 Abs. 1 lit. f)
DSGVO verarbeitet werden. Insbesondere ist ein Widerspruch gegen die Datenverarbeitung zum Zwecke der Direktwerbung
statthaft.</p>
<p>Ebenfalls hast du als Nutzer und Betroffenen nach Art. 21 DSGVO das Recht auf Widerspruch gegen die künftige
Verarbeitung der dich betreffenden Daten, sofern die Daten durch den Anbieter nach Maßgabe von Art. 6 Abs. 1
lit. f)
DSGVO verarbeitet werden. Insbesondere ist ein Widerspruch gegen die Datenverarbeitung zum Zwecke der
Direktwerbung
statthaft.</p>
<p>Du hast gemäß denVorschriften der Datenschutzgrundverordnung (DSGVO) ein Auskunftsrecht über die zu deiner Person
gespeicherten Daten, einen Berichtigungsanspruch sowie bei Vorliegen der rechtlichen Voraussetzungen einen
Anspruch auf Einschränkung der Verarbeitung und Löschung.</p>
<p>Du hast gemäß denVorschriften der Datenschutzgrundverordnung (DSGVO) ein Auskunftsrecht über die zu deiner Person
gespeicherten Daten, einen Berichtigungsanspruch sowie bei Vorliegen der rechtlichen Voraussetzungen einen
Anspruch auf Einschränkung der Verarbeitung und Löschung.</p>
<p>Eine Auskunft / Löschung kann entweder in den entsprechenden Diensten über die persönlichen Einstellungen angefordert
werden oder per E-Mail Kontakt erfragt werden.</p>
<p>Eine Auskunft / Löschung kann entweder in den entsprechenden Diensten über die persönlichen Einstellungen
angefordert
werden oder per E-Mail Kontakt erfragt werden.</p>
<h3>III. Informationen zur Datenverarbeitung</h3>
<h3>III. Informationen zur Datenverarbeitung</h3>
<p>Deine bei Nutzung des Internetauftritts verarbeiteten Daten werden gelöscht oder gesperrt, sobald der Zweck der
Speicherung entfällt, der Löschung der Daten keine gesetzlichen Aufbewahrungspflichten entgegenstehen und
nachfolgend keine anderslautenden Angaben zu einzelnen Verarbeitungsverfahren gemacht werden.</p>
<p>Deine bei Nutzung des Internetauftritts verarbeiteten Daten werden gelöscht oder gesperrt, sobald der Zweck der
Speicherung entfällt, der Löschung der Daten keine gesetzlichen Aufbewahrungspflichten entgegenstehen und
nachfolgend keine anderslautenden Angaben zu einzelnen Verarbeitungsverfahren gemacht werden.</p>
<h4>Serverdaten</h4>
<h4 id="Serverdaten">Serverdaten</h4>
<p>Aus technischen Gründen, werden Daten durch deinen Internet-Browser an den Server übermittelt. Soweit technisch
möglich, werden Daten wie u.a. Typ und Version deines Internetbrowsers, das Betriebssystem, die Website, von der aus
du auf unseren Internetauftritt gewechselt hast (Referrer URL), die Website(s) des Internetauftritts, die du
besuchst, Datum und Uhrzeit des jeweiligen Zugriffs sowie die IP-Adresse des Internetanschlusses, von dem aus die
Nutzung unseres Internetauftritts erfolgt, nicht(!) erhoben.</p>
<p>Aus technischen Gründen, werden Daten durch deinen Internet-Browser an den Server übermittelt. Soweit technisch
möglich, werden Daten wie u.a. Typ und Version deines Internetbrowsers, das Betriebssystem, die Website, von der
aus
du auf unseren Internetauftritt gewechselt hast (Referrer URL), die Website(s) des Internetauftritts, die du
besuchst, Datum und Uhrzeit des jeweiligen Zugriffs sowie die IP-Adresse des Internetanschlusses, von dem aus
die
Nutzung unseres Internetauftritts erfolgt, nicht(!) erhoben.</p>
<p>Da unser Interesse im Schutz dieser personenbezogenen Daten liegt, werden diese Daten generell nicht erhoben. Zur
Verbesserung, Stabilität, Funktionalität und Sicherheit unseres Internetauftritts ist jedoch eine temporäre
Erhebung möglich. Diese Speicherung erfolgt auf der Rechtsgrundlage von Art. 6 Abs. 1 lit. f) DSGVO.</p>
<p>Da unser Interesse im Schutz dieser personenbezogenen Daten liegt, werden diese Daten generell nicht erhoben. Zur
Verbesserung, Stabilität, Funktionalität und Sicherheit unseres Internetauftritts ist jedoch eine temporäre
Erhebung möglich. Diese Speicherung erfolgt auf der Rechtsgrundlage von Art. 6 Abs. 1 lit. f) DSGVO.</p>
<p>Sollten diese so erhobenen Daten vorübergehend in sog. Server-Log-Files gespeichert werden, geschieht dies jedoch
nicht gemeinsam mit anderen Daten von dir.</p>
<p>Sollten diese so erhobenen Daten vorübergehend in sog. Server-Log-Files gespeichert werden, geschieht dies jedoch
nicht gemeinsam mit anderen Daten von dir.</p>
<p>Die Daten werden spätestens nach 14 Tagen wieder gelöscht.</p>
<p>Die Daten werden spätestens nach 14 Tagen wieder gelöscht.</p>
<h4>Kontaktanfragen / Kontaktmöglichkeit</h4>
<h4>Kontaktanfragen / Kontaktmöglichkeit</h4>
<p>Sofern Du per Kontaktformular oder E-Mail mit uns in Kontakt trittst, werden die dabei von dir angegebenen Daten
zur Bearbeitung deiner Anfrage genutzt. Die Angabe der Daten ist zur Bearbeitung und Beantwortung deiner Anfrage
erforderlich - ohne deren Bereitstellung können wir deine Anfrage nicht oder allenfalls eingeschränkt beantworten.
</p>
<p>Sofern Du per Kontaktformular oder E-Mail mit uns in Kontakt trittst, werden die dabei von dir angegebenen Daten
zur Bearbeitung deiner Anfrage genutzt. Die Angabe der Daten ist zur Bearbeitung und Beantwortung deiner Anfrage
erforderlich - ohne deren Bereitstellung können wir deine Anfrage nicht oder allenfalls eingeschränkt
beantworten.
</p>
<p>Rechtsgrundlage für die Verarbeitung dieser Daten ist Art. 6 Abs. 1 lit. b) DSGVO.</p>
<p>Rechtsgrundlage für die Verarbeitung dieser Daten ist Art. 6 Abs. 1 lit. b) DSGVO.</p>
<p>Deine Daten werden gelöscht, sofern deine Anfrage abschließend beantwortet worden ist und der Löschung keine
gesetzlichen Aufbewahrungspflichten entgegenstehen, wie bspw. bei einer sich etwaig anschließenden
Vertragsabwicklung.</p>
<p>Deine Daten werden gelöscht, sofern deine Anfrage abschließend beantwortet worden ist und der Löschung keine
gesetzlichen Aufbewahrungspflichten entgegenstehen, wie bspw. bei einer sich etwaig anschließenden
Vertragsabwicklung.</p>
<h4>Nutzung des Dienstes Pretix</h4>
<h4 id="Pretix">Nutzung des Dienstes Pretix</h4>
<h5>Gespeicherte Daten</h5>
<h5>Gespeicherte Daten</h5>
<p>Die folgenden Daten werden durch den Dienst Pretix erfasst und gespeichert:
<p>
<p>Die folgenden Daten werden durch den Dienst Pretix erfasst und gespeichert:
<p>
<table border="1">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Betroffene Benutzer / Speicherfrist</th>
<th>Verwendungszweck / Weitergabe an Dritte</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>Cookies</strong>
<p>Zufällig generierte IDs, technisch bedingte Parameter</p>
</td>
<td>
<p>alle Besucher der Seite / Sitzungsende (Beenden des Browsers)</p>
</td>
<td>
<p>Wiedererkennung des Benutzers während der Nutzung der Anwendung</p>
<p>keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Rechnungsdaten / Mitgliedsdaten</strong>
<p>E-Mail Adresse, Name, Anschrift (freiwillig: Kommentar, Referenz)</p>
</td>
<td>
<p>Benutzer mit getätigter Bestellung / bis zur Löschung</p>
</td>
<td>
<p>Durchführung der Bestellung, interne Auflistung der Vereinsmitglieder, Archivierung für Steuerprüfung
</p>
<p>keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Bestelldaten</strong>
<p>Datum, Status, Menge sowie Art der Bestellung</p>
</td>
<td>
<p>Benutzer mit getätigter Bestellung / bis zur Löschung</p>
</td>
<td>
<p>Durchführung der Bestellung, automatische Erinnerung für Mitglieder</p>
<p>Keine Weitergabe an Dritte</p>
</td>
</tr>
</tbody>
</table>
<table border="1">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Betroffene Benutzer / Speicherfrist</th>
<th>Verwendungszweck / Weitergabe an Dritte</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>Cookies</strong>
<p>Zufällig generierte IDs, technisch bedingte Parameter</p>
</td>
<td>
<p>alle Besucher der Seite / Sitzungsende (Beenden des Browsers)</p>
</td>
<td>
<p>Wiedererkennung des Benutzers während der Nutzung der Anwendung</p>
<p>keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Rechnungsdaten / Mitgliedsdaten</strong>
<p>E-Mail Adresse, Name, Anschrift (freiwillig: Kommentar, Referenz)</p>
</td>
<td>
<p>Benutzer mit getätigter Bestellung / bis zur Löschung</p>
</td>
<td>
<p>Durchführung der Bestellung, interne Auflistung der Vereinsmitglieder, Archivierung für
Steuerprüfung
</p>
<p>keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Bestelldaten</strong>
<p>Datum, Status, Menge sowie Art der Bestellung</p>
</td>
<td>
<p>Benutzer mit getätigter Bestellung / bis zur Löschung</p>
</td>
<td>
<p>Durchführung der Bestellung, automatische Erinnerung für Mitglieder</p>
<p>Keine Weitergabe an Dritte</p>
</td>
</tr>
</tbody>
</table>
<h4>Nutzung des Dienstes we.bstly</h4>
<h4 id="we.bstly">Nutzung des Dienstes we.bstly</h4>
<h5>Gespeicherte Daten</h5>
<h5>Gespeicherte Daten</h5>
<p>Die folgenden Daten werden durch den Dienst we.bstly erfasst und gespeichert:
<p>
<p>Die folgenden Daten werden durch den Dienst we.bstly erfasst und gespeichert:
<p>
<table border="1">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Betroffene Benutzer / Speicherfrist</th>
<th>Verwendungszweck / Weitergabe an Dritte</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>Cookies</strong>
<p>Zufällig generierte IDs, technisch bedingte Parameter</p>
</td>
<td>
<p>alle Besucher der Seite / Sitzungsende (Beenden des Browsers)</p>
<p>Benutzer der „automatischen Anmeldung“ / bis zur aktiven Beendigung der Sitzung</p>
</td>
<td>
<p>Wiedererkennung des Benutzers während der Nutzung der Anwendung</p>
<p>Wiedererkennung des Benutzers bei „automatischer Anmeldung“</p>
<p>keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Account-Daten</strong>
<p>Benutzername, öffentlicher PGP Schlüssel (freiwillig: E-Mail Adresse)</p>
</td>
<td>
<p>Benutzer mit Account / bis zur Löschung</p>
</td>
<td>
<p>Identifizierung für Login, Nutzung weiterer Diensten</p>
<p>keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<p>Passwort</p>
</td>
<td>
<p>Keine permanente Speicherung, direkte Weitergabe an Authentifizierungsserver</p>
</td>
<td>
<p>Authentifizierung (Login)</p>
<p>Keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Einstellungen / Eigenschaften</strong>
<p>Berechtigungen und Quotas (freiwillig: Parameter Zweifaktor Authentifizierung)</p>
</td>
<td>
<p>Benutzer mit Account / siehe Account-Daten</p>
</td>
<td>
<p>Nutzung weiterer Diensten, Steuerung des Login Prozesses</p>
<p>Keine Weitergabe an Dritte</p>
</td>
</tr>
</tbody>
</table>
<table border="1">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Betroffene Benutzer / Speicherfrist</th>
<th>Verwendungszweck / Weitergabe an Dritte</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>Cookies</strong>
<p>Zufällig generierte IDs, technisch bedingte Parameter</p>
</td>
<td>
<p>alle Besucher der Seite / Sitzungsende (Beenden des Browsers)</p>
<p>Benutzer der „automatischen Anmeldung“ / bis zur aktiven Beendigung der Sitzung</p>
</td>
<td>
<p>Wiedererkennung des Benutzers während der Nutzung der Anwendung</p>
<p>Wiedererkennung des Benutzers bei „automatischer Anmeldung“</p>
<p>keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Account-Daten</strong>
<p>Benutzername, öffentlicher PGP Schlüssel (freiwillig: E-Mail Adresse), Profildaten (freiwillig)
</p>
</td>
<td>
<p>Benutzer mit Account / bis zur Löschung</p>
</td>
<td>
<p>Identifizierung für Login, Nutzung weiterer Diensten</p>
<p>Weitergabe nur durch aktive Einstellung, ansonsten keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<p>Passwort</p>
</td>
<td>
<p>Keine permanente Speicherung, direkte Weitergabe an Authentifizierungsserver</p>
</td>
<td>
<p>Authentifizierung (Login)</p>
<p>Keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Einstellungen / Eigenschaften</strong>
<p>Berechtigungen und Quotas (freiwillig: Parameter Zweifaktor Authentifizierung)</p>
</td>
<td>
<p>Benutzer mit Account / siehe Account-Daten</p>
</td>
<td>
<p>Nutzung weiterer Diensten, Steuerung des Login Prozesses</p>
<p>Keine Weitergabe an Dritte</p>
</td>
</tr>
</tbody>
</table>
<h4>Nutzung des Dienstes Nextcloud</h4>
<h4 id="Nextcloud">Nutzung des Dienstes Nextcloud</h4>
<h5>Gespeicherte Daten</h5>
<h5>Gespeicherte Daten</h5>
<p>Die folgenden Daten werden durch den Dienst Nextcloud erfasst und gespeichert:
<p>
<p>Die folgenden Daten werden durch den Dienst Nextcloud erfasst und gespeichert:
<p>
<table border="1">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Betroffene Benutzer / Speicherfrist</th>
<th>Verwendungszweck / Weitergabe an Dritte</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>Cookies</strong>
<p>Zufällig generierte IDs, technisch bedingte Parameter</p>
</td>
<td>
<p>alle Besucher der Seite / Sitzungsende (Beenden des Browsers)</p>
<p>Benutzer der „automatischen Anmeldung“ / 16 Tage nach letzter Nutzung</p>
</td>
<td>
<p>Wiedererkennung des Benutzers während der Nutzung der Anwendung</p>
<p>Wiedererkennung des Benutzers bei „automatischer Anmeldung“</p>
<p>keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Account-Daten</strong>
<p>Benutzername (freiwillig: E-Mail Adresse)</p>
</td>
<td>
<p>Benutzer mit Account / bis zur Löschung</p>
</td>
<td>
<p>Suche nach Benutzern beim Teilen von Inhalten, Senden von Benachrichtigungen</p>
<p>Weitergabe an alle Nutzer</p>
</td>
</tr>
<tr>
<td>
<strong>Einstellungen/ Eigenschaften</strong>
<p>Zeitstempel letztes Login, Speicherplatzkontingent, Speicherplatzkauf / Laufzeit, Sprache,
vorgenommene persönliche Einstellungen</p>
</td>
<td>
<p>Benutzer mit Account / siehe Account-Daten</p>
</td>
<td>
<p>Erkennung inaktiver Benutzer, Speicherplatzzuweisung, persönliche Anpassung der Oberfläche,
Benachrichtigungen, etc.</p>
<p>Keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Aktivitäten</strong>
<p>Auflistung der im System durchgeführten Aktionen, z.B. Upload von Dateien</p>
</td>
<td>
<p>Benutzer mit Account / 14 Tage</p>
</td>
<td>
<p>Nachvollziehbarkeit von Änderungen</p>
<p>Weitergabe individuell vom Nutzer einstellbar</p>
</td>
</tr>
<tr>
<td>
<strong>strukturierte Daten</strong>
<p>Daten, welche von Apps in der Datenbank abgelegt werden</p>
</td>
<td>
<p>Benutzer mit Account / maximale Speicherfrist siehe Account-Daten, ansonsten abhängig von der
jeweiligen App</p>
</td>
<td>
<p>Nutzung der jeweiligen Apps</p>
<p>Weitergabe von in Apps erfassten Daten individuell vom Nutzer einstellbar</p>
</td>
</tr>
<tr>
<td>
<strong>Dateien</strong>
<p>Dateien, welche mit der „Dateien“-Anwendung oder externen Clients abgelegt werden</p>
</td>
<td>
<p>Benutzer mit Account / siehe Account-Daten</p>
</td>
<td>
<p>Nutzung der „Dateien“-App oder Clients für verschiedene Plattformen zur Dateisynchronisierung, Teilen
von Dateien mit Dritten</p>
<p>Weitergabe von Dateien individuell vom Nutzer einstellbar</p>
</td>
</tr>
</tbody>
</table>
<table border="1">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Betroffene Benutzer / Speicherfrist</th>
<th>Verwendungszweck / Weitergabe an Dritte</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>Cookies</strong>
<p>Zufällig generierte IDs, technisch bedingte Parameter</p>
</td>
<td>
<p>alle Besucher der Seite / Sitzungsende (Beenden des Browsers)</p>
<p>Benutzer der „automatischen Anmeldung“ / 16 Tage nach letzter Nutzung</p>
</td>
<td>
<p>Wiedererkennung des Benutzers während der Nutzung der Anwendung</p>
<p>Wiedererkennung des Benutzers bei „automatischer Anmeldung“</p>
<p>keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Account-Daten</strong>
<p>Benutzername (freiwillig: E-Mail Adresse)</p>
</td>
<td>
<p>Benutzer mit Account / bis zur Löschung</p>
</td>
<td>
<p>Suche nach Benutzern beim Teilen von Inhalten, Senden von Benachrichtigungen</p>
<p>Weitergabe an alle Nutzer</p>
</td>
</tr>
<tr>
<td>
<strong>Einstellungen/ Eigenschaften</strong>
<p>Zeitstempel letztes Login, Speicherplatzkontingent, Speicherplatzkauf / Laufzeit, Sprache,
vorgenommene persönliche Einstellungen</p>
</td>
<td>
<p>Benutzer mit Account / siehe Account-Daten</p>
</td>
<td>
<p>Erkennung inaktiver Benutzer, Speicherplatzzuweisung, persönliche Anpassung der Oberfläche,
Benachrichtigungen, etc.</p>
<p>Keine Weitergabe an Dritte</p>
</td>
</tr>
<tr>
<td>
<strong>Aktivitäten</strong>
<p>Auflistung der im System durchgeführten Aktionen, z.B. Upload von Dateien</p>
</td>
<td>
<p>Benutzer mit Account / 14 Tage</p>
</td>
<td>
<p>Nachvollziehbarkeit von Änderungen</p>
<p>Weitergabe individuell vom Nutzer einstellbar</p>
</td>
</tr>
<tr>
<td>
<strong>strukturierte Daten</strong>
<p>Daten, welche von Apps in der Datenbank abgelegt werden</p>
</td>
<td>
<p>Benutzer mit Account / maximale Speicherfrist siehe Account-Daten, ansonsten abhängig von der
jeweiligen App</p>
</td>
<td>
<p>Nutzung der jeweiligen Apps</p>
<p>Weitergabe von in Apps erfassten Daten individuell vom Nutzer einstellbar</p>
</td>
</tr>
<tr>
<td>
<strong>Dateien</strong>
<p>Dateien, welche mit der „Dateien“-Anwendung oder externen Clients abgelegt werden</p>
</td>
<td>
<p>Benutzer mit Account / siehe Account-Daten</p>
</td>
<td>
<p>Nutzung der „Dateien“-App oder Clients für verschiedene Plattformen zur Dateisynchronisierung,
Teilen
von Dateien mit Dritten</p>
<p>Weitergabe von Dateien individuell vom Nutzer einstellbar</p>
</td>
</tr>
</tbody>
</table>
<h4>Nutzung des Dienstes E-Mail Postfach</h4>
<h4 id="E-Mail">Nutzung des Dienstes E-Mail Postfach</h4>
<h5>Gespeicherte Daten</h5>
<h5>Gespeicherte Daten</h5>
<p>Die folgenden Daten werden durch den Dienst E-Mail Postfach erfasst und gespeichert:
<p>
<p>Die folgenden Daten werden durch den Dienst E-Mail Postfach erfasst und gespeichert:
<p>
<table border="1">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Betroffene Benutzer / Speicherfrist</th>
<th>Verwendungszweck / Weitergabe an Dritte</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>E-Mails</strong>
<p>Empfangene und gesendete E-Mails</p>
</td>
<td>
<p>Benutzer mit E-Mail Postfach / bis zur Löschung</p>
</td>
<td>
<p>Speicherung der E-Mails zur Abfrage</p>
<p>Jeweilige Sender & Empfänger der E-Mail</p>
</td>
</tr>
</tbody>
</table>
<table border="1">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Betroffene Benutzer / Speicherfrist</th>
<th>Verwendungszweck / Weitergabe an Dritte</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>E-Mails</strong>
<p>Empfangene und gesendete E-Mails</p>
</td>
<td>
<p>Benutzer mit E-Mail Postfach / bis zur Löschung</p>
</td>
<td>
<p>Speicherung der E-Mails zur Abfrage</p>
<p>Jeweilige Sender & Empfänger der E-Mail</p>
</td>
</tr>
</tbody>
</table>
<h4 id="Workadventure">Nutzung des Dienstes Workadventure</h4>
<h4>Sicherheit</h4>
<h5>Gespeicherte Daten</h5>
<p>Sämtliche Daten werden verschlüsselt übertragen. Die Nutzung einer unverschlüsselten Verbindung zum Server ist
technisch ausgeschlossen.</p>
<p>Im Dienst Workadventure können weitere Dienste eingebunden sein, wie z.B. Jitsi Meet. Außerdem können externe
Webseiten geöffnet werden, es werden allerdings keine erfassten Daten an diese Webseiten weitergegeben!</p>
<p>Zusätzliche Sicherheitsfunktionen, wie 2-Faktor-Authentifizierung und anwendungsspezifische Logins werden unterstützt
und können in den Einstellungen aktiviert werden.</p>
<p>Die folgenden Daten werden durch den Dienst Workadventure erfasst:
<p>
<h4>Rechenzentrum</h4>
<table border="1">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Betroffene Benutzer / Speicherfrist</th>
<th>Verwendungszweck / Weitergabe an Dritte</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>Username</strong>
<p>Gesetzter Username</p>
</td>
<td>
<p>Benutzer mit gültiger Session / bis zur Beendigung der Session</p>
</td>
<td>
<p>Identifizierung des Avatars</p>
<p>Andere Benutzer mit gültiger Session</p>
</td>
</tr>
<tr>
<td>
<strong>Audiodaten</strong>
<p>(optional) Audiodaten des freigegebenen Mikrofons</p>
</td>
<td>
<p>Benutzer mit freigegebenen Mikrofon / WICHTIG: die Daten werden nicht an den Server übertragen
sondern direkt an die anderen Benutzer in der Nähe gesendet!</p>
</td>
<td>
<p>Direkte Gespräche mit anderen Benutzern</p>
<p>Andere Benutzer in direkter Nähe zum Avatar</p>
</td>
</tr>
<tr>
<td>
<strong>Videodaten</strong>
<p>(optional) Videodaten der freigegebenen Kamera</p>
</td>
<td>
<p>Benutzer mit freigegebener Kamera / WICHTIG: die Daten werden nicht an den Server übertragen
sondern
direkt an die anderen Benutzer in der Nähe gesendet!</p>
</td>
<td>
<p>Direkte Gespräche mit anderen Benutzern</p>
<p>Andere Benutzer in direkter Nähe zum Avatar</p>
</td>
</tr>
</tbody>
</table>
<p>Die Daten werden im Rechenzentrum der <a href="https://www.netcup.de/ueber-netcup/rechenzentrum.php"
target="_blank">netcup GmbH</a> gespeichert. Eine regelmäßige, automatisierte Datensicherung der Bestandsdaten wird durchgeführt.
</p>
<h4 id="Jitsi">Nutzung des Dienstes Jitsi Meet</h4>
<h5>Gespeicherte Daten</h5>
<p>Die folgenden Daten werden durch den Dienst Jitsi Meet erfasst:
<p>
<table border="1">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Betroffene Benutzer / Speicherfrist</th>
<th>Verwendungszweck / Weitergabe an Dritte</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<strong>Benutzername</strong>
<p>Gesetzter Benutzername</p>
</td>
<td>
<p>Benutzer mit gültiger Session / bis zur Beendigung der Session</p>
</td>
<td>
<p>Anzeige des Benutzernamen an andere Benutzer</p>
<p>Andere Benutzer im Konferenzraum</p>
</td>
</tr>
<tr>
<td>
<strong>Konferenzraum-Id</strong>
<p>Id des beigetretenen Konferenzraums</p>
</td>
<td>
<p>Benutzer mit gültiger Session / bis zur Beendigung der Session</p>
</td>
<td>
<p>Zuweisung des Users zum Konferenzraum</p>
<p>/</p>
</td>
</tr>
<tr>
<td>
<strong>Audiodaten</strong>
<p>(optional) Audiodaten des freigegebenen Mikrofons</p>
</td>
<td>
<p>Benutzer mit freigegebenen Mikrofon / Keine permanente Speicherung</p>
</td>
<td>
<p>Gespräche mit anderen Benutzern im Konferenzraum</p>
<p>Andere Benutzer im Konferenzraum</p>
</td>
</tr>
<tr>
<td>
<strong>Videodaten</strong>
<p>(optional) Videodaten der freigegebenen Kamera</p>
</td>
<td>
<p>Benutzer mit freigegebener Kamera / Keine permanente Speicherung</p>
</td>
<td>
<p>Gespräche mit anderen Benutzern im Konferenzraum</p>
<p>Andere Benutzer im Konferenzraum</p>
</td>
</tr>
<tr>
<td>
<strong>Textnachrichten</strong>
<p>(optional) Textnachrichten die der Benutzer in den Chat sendet</p>
</td>
<td>
<p>Benutzer, die Chat-Nachrichten schreiben / Keine permanente Speicherung</p>
</td>
<td>
<p>Textnachrichten an andere Benutzern im Konferenzraum</p>
<p>Andere Benutzer im Konferenzraum</p>
</td>
</tr>
</tbody>
</table>
<h4 id="Sicherheit">Sicherheit</h4>
<p>Sämtliche Daten werden verschlüsselt übertragen. Die Nutzung einer unverschlüsselten Verbindung zum Server ist
technisch ausgeschlossen.</p>
<p>Zusätzliche Sicherheitsfunktionen, wie 2-Faktor-Authentifizierung und anwendungsspezifische Logins werden
unterstützt
und können in den Einstellungen aktiviert werden.</p>
<h4 id="Rechenzentrum">Rechenzentrum</h4>
<p>Die Daten werden im Rechenzentrum der <a href="https://www.netcup.de/ueber-netcup/rechenzentrum.php"
target="_blank">netcup GmbH</a> gespeichert. Eine regelmäßige, automatisierte Datensicherung der
Bestandsdaten
wird durchgeführt.
</p>
</body>
</html>

View File

@ -3,5 +3,5 @@
Daten in der Nextcloud sind generell verschlüsselt, für volle Sicherheit deiner Dateien kannst du allerdings auch
die Ende-zu-Ende-Verschlüsselung der Nextcloud nutzen.</p>
<p>Über Nextcloud werden wir euch auch mit allen wichtigen Informationen über "Bastelei (bald e.V.)" informieren.
<p>Über Nextcloud werden wir euch auch mit allen wichtigen Informationen über "Bastelei e. V." informieren.
Des weiteren bietet Nextcloud auch einige Community-Funktionen, die wir gerne mit euch nutzen möchten.</p>

View File

@ -0,0 +1,120 @@
<h2>Nutzungsbedingungen</h2>
<h3>Bereitstellung</h3>
<p>Mit we.bstly stellt der <a href="https://www.bstly.de" target="_blank">Bastelei e. V.</a> eine Plattform
bereit, um verschiedene digitale Services zeitlich befristet zur Verfügung zu stellen. </p>
<p>we.bstly und damit verbundene Services stehen allen Vereinsmitgliedern des Bastelei e. V. sowie allen
NutzerInnen, die die entsprechenden Services direkt gebucht haben, zur Verfügung.</p>
<p>Gegenstand der Nutzung ist die Bereitstellung we.bstly und den damit verbundenen Services zur Online-Nutzung über das
Internet und die Übermittlung und Speicherung von Daten und Dateien der NutzerInnen.</p>
<p>we.bstly sowie die verschiedenen Services sind einzeln mit ihren Funktionen unter <a href="/services">Aktive
Services</a> aufgelistet.</p>
<h3>Nutzungsrecht</h3>
<p>Die NutzerInnen haben für die Laufzeit der Nutzung das beschränkte, einfache, nicht übertragbare Recht,
we.bstly und damit verbundene Services über das Internet für eigene Zwecke zu nutzen. Darüberhinausgehende
Rechte bestehen nicht.</p>
<p>Die NutzerInnen sind nicht berechtigt, we.bstly und damit verbundene Services Dritten zugänglich zu machen.
Ausgenommen sind explizite Funktionen der einzelnen Services, deren Zweck im Zugang für Dritte liegt.</p>
<h3>Datensicherheit</h3>
<p>we.bstly und damit verbundene Services haben Sicherheitsmerkmale implementiert, die Schutz vor Verlust, Missbrauch
und Manipulation der Daten und Dateien bieten. Dennoch kann ein 100% Schutz nicht gewährleistet werden (siehe <a
href="/terms-of-service#availability">Verfügbarkeit und Leistungsstörungen</a>).</p>
<p>Die NutzerInnen sind für die Daten und Dateien, die sie in we.bstly und damit verbundenen Services ablegen,
verantwortlich. Alle Daten und Dateien in we.bstly und damit verbundenen Services sind aus dem Internet erreichbar
und durch Passwort und Benutzerkennung geschützt. Auch bei starken Passwörtern können diese von Angreifern
ausgespäht werden. Deswegen müssen die NutzerInnen ihre Verbindungskennung (z. B. Login-Namen und Passwörter) geheim
halten, vor dem Zugriff durch Unberechtigte schützen und den ordnungsgemäßen Gebrauch sicherstellen. Die NutzerInnen
müssen den
Bastelei e. V. unverzüglich informieren, sobald sie Kenntnis davon erlangen, dass unbefugten Dritten
ihr Passwort bekannt ist bzw. Ihnen eine Verletzung der Datensicherheit bekannt wird oder von ihnen eine solche
vermutet wird.</p>
<h3>Schutz des Rechenzentrums</h3>
<p>Die NutzerInnen dürfen keine Daten und Dateien speichern oder versenden, die nach ihrer Art oder
Beschaffenheit geeignet sind, den Bestand oder den Betrieb des Rechenzentrums oder des Datennetzes zu gefährden.</p>
<p>Die NutzerInnen müssen jedweden Versuch unterlassen, selbst oder durch Dritte Informationen oder Daten und
Dateien unbefugt abzurufen oder in die software- und hardwaretechnischen Systeme einzugreifen oder eingreifen zu
lassen oder in die Datennetze unbefugt einzudringen.</p>
<p>Ebenfalls untersagt ist jede Handlung, die geeignet ist, den ordnungsgemäßen Betrieb we.bstly und damit verbundenen
Services zu beeinträchtigen.</p>
<h3 id="availability">Verfügbarkeit und Leistungsstörungen</h3>
<p>we.bstly sowie einzelne Services können nicht bereitgestellt werden bei</p>
<ul>
<li>Wartungsarbeiten zur Sicherstellung und Sicherung des Betriebs (diese werden zeitnah angekündigt)</li>
<li>Faktoren, die außerhalb der Kontrolle des Bastelei e. V. liegen (z. B. Naturkatastrophen, Kriege,
Terroranschläge, Aufstände oder staatliche Maßnahmen)</li>
<li>gravierenden Störungen des Betriebs, die durch Services, Hardware oder Software der NutzerInnen oder von Dritten
verursacht wurden.</li>
</ul>
<p>Ansprüche der NutzerInnen gegenüber dem Bastelei e. V. bestehen in diesen Fällen nicht.
</p>
<h3>Verfügbarkeit und Haftung</h3>
<p>we.bstly und damit verbundene Services werden dem Nutzer ohne Gewährleistung zur Verfügung gestellt. Der Bastelei
(bald e. V.) übernimmt bezüglich der Inhalte keine Gewähr und leistet keine Zusicherungen hinsichtlich
Eigenschaften. Der Bastelei e. V. übernimmt zudem keine Garantie hinsichtlich der Richtigkeit und Aktualität
der zur Verfügung gestellten Inhalte.</p>
<p>Der Bastelei e. V. haftet nicht für Schäden, die durch die Nutzung entstehen, es sei denn, die betreffenden
Schäden sind auf vorsätzliches Fehlverhalten, grobe Fahrlässigkeit oder die Verletzung von Pflichten nach dem
Produkthaftungsgesetz zurückzuführen.</p>
<h3>Verbot und Haftung bei Daten und Dateien mit rechtswidrigen Inhalten</h3>
<p>In we.bstly und damit verbundenen Services dürfen die NutzerInnen keine Daten und Dateien in rechtswidriger Weise
oder mit rechtswidrigem Inhalt übermitteln (unter anderem sind die nationalen und internationalen Schutzrechte,
insbesondere Marken- und Urheberrechte sowie die Datenschutzbestimmungen zu beachten). Geltendes Recht und die
Rechte Dritter
sind zu beachten. Des weiteren nicht erlaubt ist außerdem das Verbreiten von Inhalten, die
<ul>
<li>Rassismus</li>
<li>Gewaltverherrlichung und Extremismus irgendwelcher Art</li>
<li>Aufrufe und Anstiftung zu Straftaten und Gesetzesverstößen, Drohungen gegen Leib, Leben oder Eigentum</li>
<li>Hetzen gegen Personen oder Unternehmen</li>
<li>persönlichkeitsverletzende Äußerungen, Verleumdung, Ehrverletzung und üble Nachrede von Nutzern und Dritten
sowie Verstöße gegen das Lauterkeitsrecht</li>
<li>urheberrechtsverletzende Inhalte oder andere Verletzungen von Immaterialgüterrechten</li>
<li>sexuelle Belästigung von Nutzerinnen und Nutzern und Dritten</li>
</ul>
darstellen, betreffen oder beinhalten.
</p>
<p>Insbesondere bei Verdacht auf einen Gesetzesverstoß, bei einem Gesetzesverstoß oder bei einem schwerwiegenden Verstoß
gegen diese Nutzungsbedingungen oder gegen Rechte Dritter behält sich der Bastelei e. V. vor, das Einstellen
von Daten und Dateien abzulehnen und/oder bereits eingestellte Daten und Dateien ohne vorherige Ankündigung zu
sperren oder zu
löschen.</p>
<h3>Verstöße gegen die Nutzungsbedingungen und Sperrung des Nutzeraccounts</h3>
<p>Bei Missachtung der Nutzungsbedingungen oder Missachtung der gesetzesmäßigen Nutzung können NutzerInnen jederzeit
ohne Angabe von Gründen gesperrt oder gelöscht werden.</p>
<h3>Datenschutz</h3>
<p>Personenbezogene Daten werden ausschließlich zur Bereitstellung von we.bstly und damit verbundenen Services
verarbeitet. Die Details dazu sind in der <a href="/privacy-policy">Datenschutzerklärung</a> zu finden.
</p>
<h3>Ablauf des Nutzerkontos und Datenlöschung</h3>
<p>Nach Ablauf des Nutzerkontos wird den NutzerInnen eine Frist von 4 Wochen gewährt das Nutzerkonto zu erneuern. Nach
Ablauf dieser Frist werden alle Daten, denen keine gesetzlichen Aufbewahrungspflichten entgegenstehen,
unwiderruflich gelöscht.</p>
<h3>Freistellungsanspruch</h3>
<p>Die NutzerInnen stellen den Betreibern für den Fall der Inanspruchnahme wegen
vermeintlicher oder tatsächlicher Rechtsverletzung und/oder Verletzung von Rechten Dritter im Zusammenhang mit der
Nutzung von we.bstly sowie den damit verbundenen Services vorgenommenen Handlungen von sämtlichen sich daraus
ergebenen Ansprüchen Dritter frei. Darüber hinaus verpflichten sich die NutzerInnen, alle Kosten zu ersetzen, die
dem Betreiber durch die Inanspruchnahme durch Dritte entstehen. Zu den erstattungsfähigen Kosten zählen auch die
Kosten einer angemessenen Rechtsverteidigung.</p>
<p>Auf den vorliegenden Vertrag ist ausschließlich deutsches Recht anwendbar.</p>

View File

@ -1,4 +1,4 @@
export const environment = {
production: true,
apiUrl : 'https://api.bstly.de'
apiUrl : 'https://api.mig.bstly.de'
};

View File

@ -177,3 +177,15 @@ mat-sidenav-container {
width: 1000px;
}
}
.text-center {
text-align: center;
}
.text-justify {
text-align: justify;
}
.text-right {
text-align: right;
}