This commit is contained in:
Lurkars 2021-03-13 09:47:25 +01:00
parent 4cd6a0028b
commit 52faaba99e
19 changed files with 109 additions and 363 deletions

2
.gitignore vendored
View File

@ -44,3 +44,5 @@ testem.log
# System Files
.DS_Store
Thumbs.db
.vscode

View File

@ -1,77 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en-US" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="51858f7cee391e44c0bb9ef6f6245fa2e79f2c40" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{currentLocale}}"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="a0843de0a64adcc7ee6a946408b6876cd8abdcae" datatype="html">
<source>English</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">14</context>
</context-group>
</trans-unit>
<trans-unit id="f0122b157c4f5c7549a55110ddc09bd1387a94d2" datatype="html">
<source>Deutsch</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">15</context>
</context-group>
</trans-unit>
<trans-unit id="92eee6be6de0b11c924e3ab27db30257159c0a7c" datatype="html">
<source>Home</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">25</context>
</context-group>
</trans-unit>
<trans-unit id="6765b4c916060f6bc42d9bb69e80377dbcb5e4e9" datatype="html">
<source>Login</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="4c78c0da1bcd65bc0598c4d9474bde165de27d7a" datatype="html">
<source>Apps</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">31</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
<source>Account</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="c8222fe3bb3794f7450c6c9287c94cf9083356dc" datatype="html">
<source>Redeem tokens</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">37</context>
</context-group>
</trans-unit>
<trans-unit id="aa487b2eb3f204d966327f3ea1c8a1b137133038" datatype="html">
<source>Get tokens</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">40</context>
</context-group>
</trans-unit>
<trans-unit id="bb694b49d408265c91c62799c2b3a7e3151c824d" datatype="html">
<source>Logout</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">43</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -16,7 +16,7 @@ import { PasswordResetComponent } from './pages/password-reset/password-reset.co
import { AccountComponent } from './pages/account/account.component';
import { RegisterComponent } from './pages/register/register.component';
import { TokensComponent } from './pages/tokens/tokens.component';
import { AppsComponent } from './pages/apps/apps.component';
import { ServicesComponent } from './pages/services/services.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';
@ -43,7 +43,7 @@ const routes: Routes = [
{ path: 'external-login/totp', component: FormLoginTotpComponent, canActivate: [AnonymousGuard] },
{ path: 'password', component: PasswordComponent, canActivate: [AnonymousGuard] },
{ path: 'password-reset', component: PasswordResetComponent, canActivate: [AnonymousGuard] },
{ path: 'apps', component: AppsComponent, canActivate: [AuthenticatedGuard] },
{ path: 'services', component: ServicesComponent, canActivate: [AuthenticatedGuard] },
{
path: 'account', component: AccountComponent, canActivate: [AuthenticatedGuard], children: [

View File

@ -30,8 +30,8 @@
<a *ngIf="auth && auth.authenticated" routerLink="/account/info" routerLinkActive="active" mat-list-item>
<mat-icon>account_circle</mat-icon> {{'account' | i18n}}
</a>
<a *ngIf="auth && auth.authenticated" routerLink="/apps" routerLinkActive="active" mat-list-item>
<mat-icon>widgets</mat-icon> {{'apps' | i18n}}
<a *ngIf="auth && auth.authenticated" routerLink="/services" routerLinkActive="active" mat-list-item>
<mat-icon>widgets</mat-icon> {{'services' | i18n}}
</a>
<a routerLink="/tokens" mat-list-item>
<mat-icon>card_giftcard</mat-icon> {{'tokens.redeem' | i18n}}

View File

@ -15,7 +15,7 @@ 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 {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';
@ -72,7 +72,7 @@ export class XhrInterceptor implements HttpInterceptor {
FormLoginComponent,
FormLoginTotpComponent,
TokensComponent,
AppsComponent,
ServicesComponent,
PermissionsComponent,
ProfileFieldsComponent, ProfileFieldDialog, ProfileFieldBlob,
QuotasComponent,

View File

@ -1,17 +0,0 @@
<h3>{{'apps' | i18n}}</h3>
<mat-card *ngFor="let app of apps">
<mat-card-header>
<mat-icon>{{'apps.' + app.name + '.icon' | i18n}}</mat-icon>
<mat-card-title>{{'apps.' + app.name + '.title' | i18n}}</mat-card-title>
<mat-card-subtitle>{{'apps.' + app.name + '.subtitle' | i18n}}</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<p>
{{ 'apps.' + app.name + '.text' | i18n}}
</p>
</mat-card-content>
<mat-card-actions>
<a href="{{app.url}}" target="_blank" mat-raised-button color="primary">{{'apps.goto' | i18n}}</a>
</mat-card-actions>
</mat-card>

View File

@ -1,21 +0,0 @@
import { Component, OnInit, Input } from '@angular/core';
import { AppService } from './../../services/app.service';
@Component({
selector: 'app-apps',
templateUrl: './apps.component.html',
styleUrls: ['./apps.component.scss']
})
export class AppsComponent implements OnInit {
apps = [];
constructor(private appService: AppService) { }
ngOnInit(): void {
this.appService.apps().subscribe((data: any) => {
this.apps = data;
})
}
}

View File

@ -15,7 +15,7 @@ export class LoginComponent implements OnInit {
form: FormGroup;
public loginInvalid: boolean;
public apiUrl = environment.apiUrl;
targetRoute = '/apps';
targetRoute = '/services';
loginModel = {};
constructor(private formBuilder: FormBuilder, private authService: AuthService, private router: Router, private route: ActivatedRoute) { }

View File

@ -0,0 +1,17 @@
<h3>{{'services' | i18n}}</h3>
<mat-card *ngFor="let service of services">
<mat-card-header>
<mat-icon>{{'services.' + service.name + '.icon' | i18n}}</mat-icon>
<mat-card-title>{{'services.' + service.name + '.title' | i18n}}</mat-card-title>
<mat-card-subtitle>{{'services.' + service.name + '.subtitle' | i18n}}</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<p>
{{ 'services.' + service.name + '.text' | i18n}}
</p>
</mat-card-content>
<mat-card-actions>
<a href="{{service.url}}" target="_blank" mat-raised-button color="primary">{{'services.goto' | i18n}}</a>
</mat-card-actions>
</mat-card>

View File

@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AppsComponent } from './apps.component';
import { ServicesComponent } from './services.component';
describe('AppsComponent', () => {
let component: AppsComponent;
let fixture: ComponentFixture<AppsComponent>;
describe('ServicesComponent', () => {
let component: ServicesComponent;
let fixture: ComponentFixture<ServicesComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AppsComponent ]
declarations: [ ServicesComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AppsComponent);
fixture = TestBed.createComponent(ServicesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

View File

@ -0,0 +1,21 @@
import { Component, OnInit, Input } from '@angular/core';
import { ServiceService } from '../../services/service.service';
@Component({
selector: 'app-services',
templateUrl: './services.component.html',
styleUrls: ['./services.component.scss']
})
export class ServicesComponent implements OnInit {
services = [];
constructor(private serviceService: ServiceService) { }
ngOnInit(): void {
this.serviceService.services().subscribe((data: any) => {
this.services = data;
})
}
}

View File

@ -6,13 +6,13 @@ import { environment } from '../../environments/environment';
@Injectable({
providedIn: 'root',
})
export class AppService {
export class ServiceService {
constructor(private http: HttpClient) {
}
apps() {
return this.http.get(environment.apiUrl + "/apps");
services() {
return this.http.get(environment.apiUrl + "/services");
}
}

View File

@ -2,11 +2,11 @@
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'permissions.name' | i18n}} </th>
<td mat-cell *matCellDef="let permission">
<mat-icon inline=true>{{'apps.' + permission.name + '.icon' | i18n}}</mat-icon>
{{'apps.' + permission.name + '.title' | i18n}}
<mat-icon inline=true>{{'services.' + permission.name + '.icon' | i18n}}</mat-icon>
{{'services.' + permission.name + '.title' | i18n}}
<mat-icon *ngIf="permission.addon">add_circle</mat-icon>
<br>
<small>{{'apps.' + permission.name + '.subtitle' | i18n}}</small>
<small>{{'services.' + permission.name + '.subtitle' | i18n}}</small>
</td>
</ng-container>

View File

@ -29,7 +29,7 @@ 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('apps.' + a.name + '.title', []), this.i18n.get('apps.' + b.name + '.title', []), isAsc);
case 'name': return this.compare(this.i18n.get('services.' + a.name + '.title', []), this.i18n.get('services.' + b.name + '.title', []), 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

@ -3,8 +3,8 @@
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'quotas.name' | i18n}} </th>
<td mat-cell *matCellDef="let quota">
<mat-icon inline=true>{{'apps.' + quota.name + '.icon' | i18n}}</mat-icon>
{{'apps.' + quota.name + '.title' | i18n}}
<mat-icon inline=true>{{'services.' + quota.name + '.icon' | i18n}}</mat-icon>
{{'services.' + quota.name + '.title' | i18n}}
</td>
</ng-container>

View File

@ -28,7 +28,7 @@ export class QuotasComponent implements OnInit {
this.quotas = data.sort((a, b) => {
const isAsc = sort.direction === 'asc';
switch(sort.active) {
case 'name': return this.compare(this.i18n.get('apps.' + a.name + '.title', []), this.i18n.get('apps.' + b.name + '.title', []), isAsc);
case 'name': return this.compare(this.i18n.get('services.' + a.name + '.title', []), this.i18n.get('services.' + b.name + '.title', []), isAsc);
case 'value': return this.compare(a.value, b.value, isAsc);
default: return 0;
}

View File

@ -1,51 +1,5 @@
{
"account": "Account",
"apps": {
".": "Apps",
"gitea": {
"icon": "code",
"subtitle": "Git-Repositories",
"text": "Alternative zu Diensten wie GitHub, Source Code von bstly-Entwicklungen",
"title": "Gitea"
},
"goto": "Gehe zur App",
"mail": {
"icon": "email",
"subtitle": "E-Mail Konto",
"text": "Catch-All an @{username}.we.bstly.de, lernender Spam-Filter und PGP Verschlüsselung.",
"title": "E-Mail Postfach"
},
"matrix": {
"icon": "question_answer",
"subtitle": "Messenger Plattform",
"text": "mit anderen Austauschen, sich Informieren oder einfach quatschen.",
"title": "Matrix"
},
"nextcloud": {
"icon": "cloud",
"subtitle": "Cloud Plattform",
"text": "Dateiverwaltung, Kalendar, Aufgabenmanagement, Kontaktmanagement, Abstimmungen und mehr.",
"title": "Nextcloud"
},
"partey": {
"icon": "celebration",
"subtitle": "Virtuelles Vereinsheim",
"text": "Digitaler Treffpunkt für Veranstaltungen oder einfach zum Abhängen.",
"title": "Partey"
},
"registration_vouchers": {
"icon": "card_giftcard",
"subtitle": "Gutschein Code für Registrierungs-Token",
"text": "Einladung um die Services des Bastelei e. V. zu nutzen",
"title": "Registrierungs-Gutscheincodes"
},
"ROLE_MEMBER": {
"icon": "loyalty",
"subtitle": "Mitgliedschaft im Bastelei e. V.",
"text": "Reguläres Mitglied im Bastelei e. V.",
"title": "Vereinsmitgliedschaft"
}
},
"cancel": "Abbrechen",
"close": "Schliessen",
"date-time-format": "dd.MM.yyyy HH:mm:ss",
@ -252,7 +206,52 @@
".": "Service nicht erreichbar",
"text": "Zurzeit scheint der Service nicht erreichbar zu sein. Wenn diese Meldung länger besteht, melde dich bitte unter admin@bstly.de!"
},
"services": {},
"services": {
".": "Dienste",
"gitea": {
"icon": "code",
"subtitle": "Git-Repositories",
"text": "Alternative zu Diensten wie GitHub, Source Code von bstly-Entwicklungen",
"title": "Gitea"
},
"goto": "Gehe zum Dienst",
"mail": {
"icon": "email",
"subtitle": "E-Mail Konto",
"text": "Catch-All an @{username}.we.bstly.de, lernender Spam-Filter und PGP Verschlüsselung.",
"title": "E-Mail Postfach"
},
"matrix": {
"icon": "question_answer",
"subtitle": "Messenger Plattform",
"text": "mit anderen Austauschen, sich Informieren oder einfach quatschen.",
"title": "Matrix"
},
"nextcloud": {
"icon": "cloud",
"subtitle": "Cloud Plattform",
"text": "Dateiverwaltung, Kalendar, Aufgabenmanagement, Kontaktmanagement, Abstimmungen und mehr.",
"title": "Nextcloud"
},
"partey": {
"icon": "celebration",
"subtitle": "Virtuelles Vereinsheim",
"text": "Digitaler Treffpunkt für Veranstaltungen oder einfach zum Abhängen.",
"title": "Partey"
},
"registration_vouchers": {
"icon": "card_giftcard",
"subtitle": "Gutschein Code für Registrierungs-Token",
"text": "Einladung um die Services des Bastelei e. V. zu nutzen",
"title": "Registrierungs-Gutscheincodes"
},
"ROLE_MEMBER": {
"icon": "loyalty",
"subtitle": "Mitgliedschaft im Bastelei e. V.",
"text": "Reguläres Mitglied im Bastelei e. V.",
"title": "Vereinsmitgliedschaft"
}
},
"software": "Software",
"sourcecode": "Quellcode",
"token": "Token",

View File

@ -1,178 +0,0 @@
{
"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",
"login": {
".": "Login",
"external": "Login",
"invalid": "The username and password were not recognised."
},
"totp": {
".": "2FA (TOTP)",
"hint": "For using TOTP (known as Google Authenticator) as second factor, please scan the QRCode with your TOTP App.",
"enable": "Enable 2FA (TOTP)",
"code": "TOTP code",
"login" : "Login",
"create": "Setup 2FA (TOTP)",
"remove": "Disable 2FA (TOTP)",
"external": "2FA (TOTP)",
"invalid": "TOTP code is invalid",
"missing": "TOTP code is missing"
},
"not-found": {
".": "Not Found",
"text": "What's Up!?"
},
"service-unavailable": {
".": "Service Unavailable",
"text": "Currently the service seems unavailable. If this message stays for long, please contact admin@bstly.de!"
},
"logout": "Logout",
"account": "Account",
"token": "Token",
"ok": "Ok",
"tokens": {
".": "Tokens",
"redeem": "Redeem Tokens",
"redeemed": "The provided token is already redeemed.",
"get": "Get Tokens",
"enter": "Enter Token",
"validate": "Validate",
"invalid": "The provided token is invalid.",
"provide-valid": "Please provide a valid token"
},
"username": {
".": "Username",
"missing": "Please provide a valid username.",
"error": "Please choose another username."
},
"password": {
".": "Password",
"forgot": "Forgot Password",
"request": "Request Password",
"reset": "Reset Password",
"change": "Change Password",
"changed": "Succeffuly changed Password!",
"current": "Current Password",
"confirm": "Confirm Password",
"not-match": "Password do not match.",
"invalid": {
"hint": "Please provide a valid password"
},
"error": {
"ILLEGAL_WHITESPACE": "Please do not use any whitespace!",
"INSUFFICIENT_DIGIT": "Please provide at least one digit!",
"INSUFFICIENT_UPPERCASE": "Please provide at leaste one uppercase character!",
"INSUFFICIENT_LOWERCASE": "Please provide at leaste one lowercase character!",
"INSUFFICIENT_SPECIAL": "Please provide at leaste one special character!",
"TOO_SHORT": "Please choose a longer password!"
}
},
"register": {
".": "Register",
"token.missing": "Please provide a valid token first!"
},
"email": {
".": "E-Mail",
"primary": "Primary E-Mail",
"invalid": "invalid E-Mail"
},
"apps": "Apps",
"app": {
"goto": "Go To App"
},
"locale": {
"en": {
"short": "EN",
"long": "English"
},
"de-informal": {
"short": "DE",
"long": "Deutsch"
}
},
"info": {
".": "Info"
},
"permissions": {
".": "Permissions",
"name": "Name",
"expires": "Expires"
},
"quotas": {
".": "Quotas",
"name": "Name",
"value": "Quota"
},
"voucher": {
".": "Voucher",
"type": "Type",
"code": "Code"
},
"vouchers": {
".": "Vouchers",
"info": "Add-On and Registration Vouchers",
"registration": "Registration",
"add-on": "Add-On",
"temp": {
".": "Temporary Vouchers",
"info": "This list your currently requested vouchers! Please store them safely, the will not get stored for you!"
},
"stored-safely": {
".": "Because we do not store any relation from your account to voucher codes, please store this voucher safely. It will not be available on refresh!",
"confirm": "I have saved my voucher safely!"
}
},
"security": {
".": "Security"
},
"software" : "Software",
"sourcecode": "Sourcecode",
"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"
}
}
}
}