initial commit

This commit is contained in:
steev 2023-10-15 20:03:11 +02:00
commit dc797d78ed
176 changed files with 23002 additions and 0 deletions

16
.browserslistrc Normal file
View File

@ -0,0 +1,16 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR

16
.editorconfig Normal file
View File

@ -0,0 +1,16 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md]
max_line_length = off
trim_trailing_whitespace = false

43
.gitignore vendored Normal file
View File

@ -0,0 +1,43 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.vscode/
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db

27
README.md Normal file
View File

@ -0,0 +1,27 @@
# ProximaTVFrontend
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 13.1.4.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

115
angular.json Normal file
View File

@ -0,0 +1,115 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"Proxima-TV-Frontend": {
"projectType": "application",
"schematics": {
"@schematics/angular:application": {
"strict": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"allowedCommonJsDependencies": [
"crypto-js"
],
"outputPath": "dist/proxima-tv-frontend",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css",
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
"node_modules/plyr/dist/plyr.css"
],
"scripts": [
"./node_modules/bootstrap/dist/js/bootstrap.min.js",
"./node_modules/chart.js/dist/chart.min.js",
"./node_modules/crypto-js/crypto-js.js"
]
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": true,
"optimization": true,
"vendorChunk": true,
"extractLicenses": true,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "Proxima-TV-Frontend:build:production"
},
"development": {
"browserTarget": "Proxima-TV-Frontend:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "Proxima-TV-Frontend:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
}
}
}
},
"defaultProject": "Proxima-TV-Frontend"
}

44
karma.conf.js Normal file
View File

@ -0,0 +1,44 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage/proxima-tv-frontend'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' }
]
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

19544
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

47
package.json Normal file
View File

@ -0,0 +1,47 @@
{
"name": "proxima-tv-frontend",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "~13.1.0",
"@angular/common": "~13.1.0",
"@angular/compiler": "~13.1.0",
"@angular/core": "~13.1.0",
"@angular/forms": "~13.1.0",
"@angular/platform-browser": "~13.1.0",
"@angular/platform-browser-dynamic": "~13.1.0",
"@angular/router": "~13.1.0",
"@tinymce/tinymce-angular": "^5.0.1",
"@types/crypto-js": "^4.1.0",
"bootstrap": "^5.1.3",
"chart.js": "^3.7.0",
"crypto-js": "^4.1.1",
"ngx-cookie-service": "^13.1.2",
"ngx-plyr": "^4.0.1",
"plyr": "^3.7.2",
"rxjs": "~7.4.0",
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^13.1.4",
"@angular/cli": "~13.1.4",
"@angular/compiler-cli": "~13.1.0",
"@types/jasmine": "~3.10.0",
"@types/node": "^17.0.12",
"jasmine-core": "~3.10.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.1.0",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "~1.7.0",
"typescript": "~4.5.2"
}
}

View File

@ -0,0 +1,10 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

View File

View File

@ -0,0 +1,3 @@
<app-navbar></app-navbar>
<router-outlet></router-outlet>
<app-footer></app-footer>

View File

@ -0,0 +1,35 @@
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'Proxima-TV-Frontend'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('Proxima-TV-Frontend');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('Proxima-TV-Frontend app is running!');
});
});

12
src/app/app.component.ts Normal file
View File

@ -0,0 +1,12 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Proxima-TV-Frontend';
}

72
src/app/app.module.ts Normal file
View File

@ -0,0 +1,72 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule, Routes } from '@angular/router';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { StatsComponent } from './stats/stats.component';
import { CommentsComponent } from './comments/comments.component';
import { HistoryComponent } from './history/history.component';
import { NavbarComponent } from './navbar/navbar.component';
import { FormsComponent } from './forms/forms.component';
import { QuestionsComponent } from './questions/questions.component';
import { ServicePreviewComponent } from './service-preview/service-preview.component';
import { SettingsComponent } from './settings/settings.component';
import { WatchComponent } from './watch/watch.component';
import { FooterComponent } from './footer/footer.component';
import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';
import { LoginModule } from './login/login.module';
import { RegisterModule } from './register/register.module';
import { HomeComponent } from './home/home.component';
import { SearchModule } from './search/search.module';
import { ErrorComponent } from './error/error.component';
import { WatchModule } from './watch/watch.module';
import { AuthGuard } from './auth.guard';
import { SearchPageComponent } from './search-page/search-page.component';
import { UploadsComponent } from './uploads/uploads.component';
import { UploadsModule } from './uploads/uploads.module';
import { ChannelComponent } from './channel/channel.component';
const routes: Routes = [
{ path: '', component: HomeComponent},
{ path: 'profile', component: StatsComponent, canActivate: [AuthGuard] },
{ path: 'watch/:watch', component: WatchComponent},
{ path: 'settings', component: SettingsComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'register/:email', component: RegisterComponent },
{ path: 'search/:query', component: SearchPageComponent },
{ path: 'upload', component: UploadsComponent, canActivate: [AuthGuard] },
{ path: 'channel/:id', component: ChannelComponent },
];
@NgModule({
declarations: [
AppComponent,
StatsComponent,
CommentsComponent,
HistoryComponent,
NavbarComponent,
FormsComponent,
QuestionsComponent,
ServicePreviewComponent,
SettingsComponent,
FooterComponent,
HomeComponent,
ErrorComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
LoginModule,
UploadsModule,
RegisterModule,
WatchModule,
RouterModule.forRoot(routes),
SearchModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { AuthGuard } from './auth.guard';
describe('AuthGuard', () => {
let guard: AuthGuard;
beforeEach(() => {
TestBed.configureTestingModule({});
guard = TestBed.inject(AuthGuard);
});
it('should be created', () => {
expect(guard).toBeTruthy();
});
});

21
src/app/auth.guard.ts Normal file
View File

@ -0,0 +1,21 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor( private authService: AuthService, private router: Router){}
canActivate(){
if(this.authService.loggedIn()){
console.log("guard")
return true;
} else {
this.router.navigate(['/login']);
return false;
}
}
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

25
src/app/auth.service.ts Normal file
View File

@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {map} from'rxjs/operators';
import { CryptoService } from './crypto.service';
import { CookiesService } from './cookies.service';
@Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(
private http: HttpClient,
private cookies:CookiesService
) { }
register(data:object){
this.http.post('http://localhost:3000/users/register',data, {})
}
loggedIn(): boolean{
// TODO: verify data against data on the server
let loggin = this.cookies.getCookie("proxima-login-cookie").split(',')
return loggin[0] != null && loggin[1] != null;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,12 @@
.channel-header {
position: static;
padding: 10px;
height: 200px;
background-color: #ecf0f1;
}
.channel-pic {
border-radius: 50%;
height: 180px;
width: 180px;
border: 1px solid black;
}

View File

@ -0,0 +1,22 @@
<div class="channel-header">
<div class="container">
<div class="row">
<div class="col-2">
<img class="channel-pic" src="https://cdn.slpnetwork.de/img/sys/users/Thesteev.png" alt="">
</div>
<div class="col-10" style="padding-top: 3%;">
<h3 style="font-weight: bold; color:#7f8c8d;">{{username}}<br>{{subscribers}} Subscribers</h3>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row" style="padding: 0;">
<div class="col-1"></div>
<div class="col-10" style="padding:0">
<div class="row" #searchList>
</div>
<div class="col-1"></div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ChannelComponent } from './channel.component';
describe('ChannelComponent', () => {
let component: ChannelComponent;
let fixture: ComponentFixture<ChannelComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ChannelComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ChannelComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,75 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Component, ElementRef, OnInit, Renderer2, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ConfigService } from '../config.service';
import { CookiesService } from '../cookies.service';
@Component({
selector: 'app-channel',
templateUrl: './channel.component.html',
styleUrls: ['./channel.component.css']
})
export class ChannelComponent implements OnInit {
@ViewChild('searchList')cl: ElementRef;
searchAmnt: number;
username: string;
subscribers: number;
constructor(
private http: HttpClient,
private rednerer: Renderer2,
private activatedRoute: ActivatedRoute,
private config: ConfigService,
private cookies: CookiesService) { }
ngOnInit(): void {
const query = {
query: this.activatedRoute.snapshot.params['id']
};
this.username = this.cookies.getCookie('proxima-login-cookie').split(',')[0];
this.subscribers = 0;
let params = new HttpParams()
.set('creator',JSON.stringify(query));
this.http.get<any>(this.config.hostname + '/videos/channel', {
params: params
}).subscribe(data => {
console.log("data arrive")
console.log(data.videos.length);
this.searchAmnt = data.length;
for(let i = 0; i < data.videos.length; i++) {
console.log(i);
// TODO: construct html for the page to load
// ALSO TODO: determing what data is needed on this exact page
const topDiv: HTMLDivElement = this.rednerer.createElement("div");
const Anchor: HTMLAnchorElement = this.rednerer.createElement("a");
const div: HTMLDivElement = this.rednerer.createElement("div");
const Img: HTMLImageElement = this.rednerer.createElement("img");
const bottomdiv: HTMLDivElement = this.rednerer.createElement("div")
const title: HTMLTitleElement = this.rednerer.createElement("h2");
const titleText = this.rednerer.createText(data.videos[i]["title"])
topDiv.appendChild(Anchor);
topDiv.classList.add("col-4");
topDiv.style.marginTop = "20px";
Anchor.appendChild(div);
Anchor.href = "/watch/" + data.videos[i]["vid_id"];
div.appendChild(Img);
div.classList.add("card");
div.classList.add("bg-dark");
div.appendChild(bottomdiv);
bottomdiv.appendChild(title);
bottomdiv.classList.add("card-img-overlay");
bottomdiv.style.backgroundColor = "rgba(0, 0, 0, 0.432)";
title.appendChild(titleText);
title.classList.add("card-title");
title.style.color = "white";
Img.classList.add("card-img");
Img.src = "https://proxima-tv.github.io/poster.jpg";
this.cl.nativeElement.prepend(topDiv);
}
});
}
}

View File

@ -0,0 +1,15 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ChannelComponent } from './channel.component';
@NgModule({
declarations: [
ChannelComponent
],
imports: [
CommonModule
]
})
export class ChannelModule { }

View File

View File

@ -0,0 +1,22 @@
<br>
<h1>Last Written Comments: </h1>
<div class="list-group">
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Video 1</h5>
</div>
<p class="mb-1">Some kind of Comment.</p>
</a>
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Video 2</h5>
</div>
<p class="mb-1">Some kind of Comment.</p>
</a>
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Video 3</h5>
</div>
<p class="mb-1">Some kind of Comment.</p>
</a>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CommentsComponent } from './comments.component';
describe('CommentsComponent', () => {
let component: CommentsComponent;
let fixture: ComponentFixture<CommentsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ CommentsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(CommentsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-comments',
templateUrl: './comments.component.html',
styleUrls: ['./comments.component.css']
})
export class CommentsComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { ConfigService } from './config.service';
describe('ConfigService', () => {
let service: ConfigService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ConfigService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,9 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ConfigService {
public hostname = "http://localhost:3000"
constructor() { }
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { CookiesService } from './cookies.service';
describe('CookiesService', () => {
let service: CookiesService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(CookiesService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,44 @@
import { Injectable } from '@angular/core';
import {CookieService} from 'ngx-cookie-service';
@Injectable({
providedIn: 'root'
})
export class CookiesService {
constructor(private service:CookieService) { }
/**
* gets given cookie name
* @param cookie the cookie to receive name
* @returns value of cookie
*/
getCookie(cookie:string){
return this.service.get(cookie);
}
/**
* get all cookies from browser
* @returns all cookies
*/
getAllCookies() {
return this.service.getAll();
}
deleteCookie(name:string){
try {
this.service.delete(name);
} catch (error) {
console.log(error);
}
}
/**
* sets specified cookies
* @param cookieName the name of the cookie to store
* @param values the value to store inside the cookie
*/
setCookie(cookieName:string, values:string):void{
// TODO: rework to fit new proper structuer
this.service.set(cookieName, values)
}
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { CryptoService } from './crypto.service';
describe('CryptoService', () => {
let service: CryptoService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(CryptoService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

62
src/app/crypto.service.ts Normal file
View File

@ -0,0 +1,62 @@
import { Injectable } from '@angular/core';
import * as CryptoJS from 'crypto-js';
@Injectable({ providedIn: 'root' })
/**
* @deprecated in its current state the cryptoservice in nonfunctional
*/
export class CryptoService {
private static secretKey = "";
static makeid(length:number):string {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); }
return result;
}
static setKey(k:string) { this.secretKey = k; }
//The set method is use for encrypt the value.
static encrypt(data:string){
var key = CryptoJS.enc.Utf8.parse(this.secretKey);
var iv = CryptoJS.enc.Utf8.parse(this.makeid(16)); // TODO: Randomize IV to reenhance security
// console.log("Key: " + key);
console.log("Initial Vector: " + iv);
var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(data.toString()), key,
{
keySize: 128 / 8,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
let out = {
"content": encrypted.toString(),
"iv": iv
};
// Instead of sending only the encrypted string, send an object with iv and encrypted data
return out;
}
//The get method is use for decrypt the value.
static decrypt(data:any){
console.log("Initial Vector: " + data['iv']);
var key = CryptoJS.enc.Utf8.parse(this.secretKey);
var decrypted = CryptoJS.AES.decrypt(data['content'], key, {
keySize: 128 / 8,
iv: data['iv'],
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
}

View File

@ -0,0 +1,41 @@
span {
margin-left: 600px;
margin-right:600px;
text-decoration: underline;
font-family: Arial, Helvetica, sans-serif;
font-size: large;
display: flex;
align-items: center;
justify-content:center;
border-style: dashed;
background-color: rgb(255,0,0) ;
align-items: center;
}
a{
margin-left: 600px;
margin-right:600px;
text-decoration: underline;
font-family: Arial, Helvetica, sans-serif;
font-size: large;
display: flex;
align-items: center;
justify-content:center;
border-style: hidden;
background-color: rgb(255,0,0) ;
align-items: center;
}
h3{
margin-left: 600px;
margin-right:600px;
text-decoration: underline;
font-family: Arial, Helvetica, sans-serif;
font-size: large;
display: flex;
align-items: center;
justify-content:center;
align-items: center;
}

View File

@ -0,0 +1,22 @@
<div class="row justify-content-center">
<div class="col-md-12 col-sm-12">
<div class="card shadow-lg border-0 rounded-lg mt-5 mx-auto" >
<h3 class="card-header display-1 text-muted text-center">
404
</h3>
<span class="card-subtitle mb-2 text-muted text-center">
Page Could Not Be Found
</span>
<div class="card-body mx-auto">
<a type="button" href="http://localhost:4200/"
class="btn btn-sm btn-info text-white"> Back To Home </a>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ErrorComponent } from './error.component';
describe('ErrorComponent', () => {
let component: ErrorComponent;
let fixture: ComponentFixture<ErrorComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ErrorComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ErrorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-error',
templateUrl: './error.component.html',
styleUrls: ['./error.component.css']
})
export class ErrorComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

View File

@ -0,0 +1,16 @@
<div class="container">
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
<div class="col-md-4 d-flex align-items-center">
<a href="/" class="mb-3 me-2 mb-md-0 text-muted text-decoration-none lh-1">
<img src="assets/logo.png" alt="Company icon" width="30" height="30">
</a>
<span class="text-muted">&copy; 2022 Proxima Studios</span>
</div>
<ul class="nav col-md-4 justify-content-end list-unstyled d-flex">
<li class="ms-3"><a class="text-muted" href="#"><i style="font-size: 32px;" class="fab fa-twitter"></i></a></li>
<li class="ms-3"><a class="text-muted" href="#"><i style="font-size: 32px;" class="fab fa-instagram"></i></a></li>
<li class="ms-3"><a class="text-muted" href="#"><i style="font-size: 32px;" class="fab fa-github"></i></a></li>
</ul>
</footer>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FooterComponent } from './footer.component';
describe('FooterComponent', () => {
let component: FooterComponent;
let fixture: ComponentFixture<FooterComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FooterComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FooterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.css']
})
export class FooterComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

View File

@ -0,0 +1,22 @@
<div style="background-image:url(https://i.pinimg.com/originals/21/5c/7f/215c7fdca6033092baa04b35c17466bd.gif); background-size: cover; height: 450px;">
<div style="background-image: url('Proxima');">
<div class="container" style="padding-top: 200px;">
<div class="row">
<div class="col-3"></div>
<div class="col-6">
<h1 style="color:white;">Register to get started</h1>
<form (submit)="redirect()">
<div class="row">
<div class="col-9">
<input type="email" class="form-control" id="frontPageEmailInput" placeholder="name@example.com" name="email">
</div>
<div class="col-3">
<button class="btn btn-success" type="submit" onclick="window.location.href = '/register/'+document.getElementById('frontPageEmailInput').value">Register</button>
</div>
</div>
</form>
</div>
<div class="col-3"></div>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsComponent } from './forms.component';
describe('FormsComponent', () => {
let component: FormsComponent;
let fixture: ComponentFixture<FormsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FormsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FormsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,20 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AppModule } from '../app.module';
@Component({
selector: 'app-forms',
templateUrl: './forms.component.html',
styleUrls: ['./forms.component.css']
})
export class FormsComponent implements OnInit {
email:any;
constructor(private router:Router) { }
ngOnInit(): void {}
redirect(){
this.router.navigate(['/register/' + this.email]);
}
}

View File

@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsComponent } from './forms.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@NgModule({
declarations: [FormsComponent],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule
]
})
export class FormModule { }

View File

View File

@ -0,0 +1,22 @@
<br>
<h1>Your Watch History: </h1>
<div class="list-group">
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Video 1</h5>
</div>
<p class="mb-1">a video description.</p>
</a>
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Video 2</h5>
</div>
<p class="mb-1">a video description.</p>
</a>
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Video 3</h5>
</div>
<p class="mb-1">a video description.</p>
</a>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HistoryComponent } from './history.component';
describe('HistoryComponent', () => {
let component: HistoryComponent;
let fixture: ComponentFixture<HistoryComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ HistoryComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(HistoryComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-history',
templateUrl: './history.component.html',
styleUrls: ['./history.component.css']
})
export class HistoryComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,6 @@
.flex-center {
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}

View File

@ -0,0 +1,10 @@
<div class="container">
<div class="row" style="padding: 0;">
<div class="col-1"></div>
<div class="col-10" style="padding:0">
<div class="row" #searchList>
</div>
<div class="col-1"></div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HomeComponent } from './home.component';
describe('HomeComponent', () => {
let component: HomeComponent;
let fixture: ComponentFixture<HomeComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ HomeComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(HomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,68 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Component, ElementRef, OnInit, Renderer2, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ConfigService } from '../config.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
@ViewChild('searchList')cl:ElementRef;
searchAmnt:number;
constructor(
private http:HttpClient,
private rednerer:Renderer2,
private activatedRoute: ActivatedRoute,
private config: ConfigService) { }
ngOnInit(): void {
const query = {
query: this.activatedRoute.snapshot.params['query']
};
let params = new HttpParams()
.set('query',JSON.stringify(query));
this.http.get<any>(this.config.hostname + '/videos/videos', {
params: params
}).subscribe(data => {
console.log("data arrive")
console.log(data.videos.length);
this.searchAmnt = data.length;
for(let i = 0; i < data.videos.length; i++) {
console.log(i);
// TODO: construct html for the page to load
// ALSO TODO: determing what data is needed on this exact page
const topDiv:HTMLDivElement = this.rednerer.createElement("div");
const Anchor:HTMLAnchorElement = this.rednerer.createElement("a");
const div:HTMLDivElement = this.rednerer.createElement("div");
const Img:HTMLImageElement = this.rednerer.createElement("img");
const bottomdiv:HTMLDivElement = this.rednerer.createElement("div")
const title: HTMLTitleElement = this.rednerer.createElement("h2");
const titleText = this.rednerer.createText(data.videos[i]["title"])
topDiv.appendChild(Anchor);
topDiv.classList.add("col-4");
topDiv.style.marginTop = "20px";
Anchor.appendChild(div);
Anchor.href = "/watch/" + data.videos[i]["vid_id"];
div.appendChild(Img);
div.classList.add("card");
div.classList.add("bg-dark");
div.appendChild(bottomdiv);
bottomdiv.appendChild(title);
bottomdiv.classList.add("card-img-overlay");
bottomdiv.style.backgroundColor = "rgba(0, 0, 0, 0.432)";
title.appendChild(titleText);
title.classList.add("card-title");
title.style.color = "white";
Img.classList.add("card-img");
Img.src = "https://proxima-tv.github.io/poster.jpg";
this.cl.nativeElement.prepend(topDiv);
}
});
}
}

View File

@ -0,0 +1,26 @@
.form-signin {
width: 100%;
max-width: 330px;
padding: 15px;
margin: auto;
}
.form-signin .checkbox {
font-weight: 400;
}
.form-signin .form-floating:focus-within {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}

View File

@ -0,0 +1,22 @@
<div class="form-signin">
<form (ngSubmit)="onSubmit()" style="margin-top: 20%;">
<h1 class="h3 mb-3 fw-normal" style="text-align: center;">Please sign in</h1>
<div class="form-floating">
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com" [(ngModel)]="logEmail" name="logEmail">
<label for="floatingInput">Email address</label>
</div>
<div class="form-floating">
<input type="password" class="form-control" id="floatingPassword" placeholder="Password" [(ngModel)]="logPassword" name="logPassword">
<label for="floatingPassword">Password</label>
</div>
<div class="checkbox mb-3">
<label>
<input type="checkbox" [(ngModel)]="remember" value="remember-me"> Remember me
</label>
</div>
<button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
<a href="/register">no account yet?</a>
</form>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LoginComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,57 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ConfigService } from '../config.service';
import { CookiesService } from '../cookies.service';
import { NavbarComponent } from '../navbar/navbar.component';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
public logEmail: any;
public logPassword: any;
public remember: any;
constructor(
private http: HttpClient,
private cookies: CookiesService,
private router: Router,
private config: ConfigService
) { }
ngOnInit(): void { }
onSubmit(): void {
const user = {
email: this.logEmail,
password: encodeURIComponent(this.logPassword.toString())
};
console.log(user);
console.log(this.remember);
let params = new HttpParams().set('user', JSON.stringify(user));
console.log(params);
// this should use the body but has to revert back to using query strings
this.http.get<any>(this.config.hostname + '/user/login', {
params: params
}).subscribe(async data => {
console.log(JSON.stringify(data));
if(this.remember){
var d = new Date();
d.setTime(d.getTime() + (7*24*60*60*1000));
var expires = "expires="+ d.toUTCString();
document.cookie = `proxima-login-cookie=${data['payload']['username']},${data['payload']['email']},${data['payload']['id']}; ${expires}; SameSite:none; Secure`;
document.cookie = `proxima-login-reload=1`;
} else {
this.cookies.setCookie('proxima-login-cookie', `${data['payload']['username']},${data['payload']['email']},${data['payload']['id']},`);
}
NavbarComponent.isLoggedIn = true;
this.router.navigate(['/profile']);
});
}
}

View File

@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { LoginComponent } from './login.component';
import { HttpClientModule } from '@angular/common/http';
import { CookieService } from 'ngx-cookie-service';
@NgModule({
declarations: [LoginComponent],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
HttpClientModule
]
})
export class LoginModule { }

View File

View File

@ -0,0 +1,35 @@
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<img src="assets/logo.png" alt="" width="30" height="30" class="d-inline-block align-text-top">
PROXIMA.TV
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<div class="row" style="width: 100%;">
<div class="col-10" style="padding-left: 25%; padding-right: 10%; padding-top: 10px;">
<form class="d-flex">
<input class="form-control me-2" id="search" type="search" placeholder="Find Your Poisen!" aria-label="Find Your Poisen!">
<a class="btn btn-outline-success" type="submit" onclick="window.location.href = '/search/'+document.getElementById('search').value">Search</a>
</form>
</div>
<div class="col-2" style="padding-top: 10px;">
<span *ngIf="!isLoggedIn"><a href="/login">Login</a> | <a href="/register">Register</a></span>
<div class="dropdown" *ngIf="isLoggedIn">
<button class="btn dropdown-toggle" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false" style="width: 100%;">
<img src="https://cdn.slpnetwork.de/img/sys/users/Thesteev.png" width="30px" height="30px" style="border-radius: 50%;"> {{username}}
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1" style="width: 100%;">
<li><a class="dropdown-item" href="/profile">Profile</a></li>
<li><a class="dropdown-item" href="/upload">Upload</a></li>
<li><a class="dropdown-item" href="/settings">Settings</a></li>
<li><a class="dropdown-item" (click)="logout()" style="color: #e74c3c;" href="#">Logout</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</nav>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NavbarComponent } from './navbar.component';
describe('NavbarComponent', () => {
let component: NavbarComponent;
let fixture: ComponentFixture<NavbarComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ NavbarComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(NavbarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,36 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../auth.service';
import { CookiesService } from '../cookies.service';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
static isLoggedIn: Boolean;
username:string;
constructor(
private cookieService: CookiesService,
private authService: AuthService,
private router:Router
) { }
isLoggedIn = false;
ngOnInit(): void {
console.log(this.authService.loggedIn());
// checks for login cookie to ensure the proper menu is shown
this.isLoggedIn = this.authService.loggedIn();
this.username = this.cookieService.getCookie('proxima-login-cookie').split(',')[0];
}
logout(){
console.log('logout')
this.cookieService.deleteCookie('proxima-login-cookie');
this.isLoggedIn = false;
this.router.navigate(['/login'])
}
}

View File

@ -0,0 +1,51 @@
<div class="container">
<div id="accordion">
<div class="card">
<div class="card-header" id="headingOne">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true"
aria-controls="collapseOne">
Was ist Proxima-Tv ?
</button>
</h5>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
<div class="card-body">
Proxima-Tv ist ein brandneuer Sreamingdienst. Wir bieten für die Premium-Nutzer eine Vielfalt von Inhalten und
das ohne Werbung
</div>
</div>
</div>
<div class="card">
<div class="card-header" id="headingTwo">
<h5 class="mb-0">
<button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false"
aria-controls="collapseTwo">
Was kann man auf Proxima-Tv sehen ?
</button>
</h5>
</div>
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordion">
<div class="card-body">
Eine Vielzahl von Videos und Filmen ohne Begrenzung und ohne zusätzlichen kosten.
</div>
</div>
</div>
<div class="card">
<div class="card-header" id="headingThree">
<h5 class="mb-0">
<button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapseThree" aria-expanded="false"
aria-controls="collapseThree">
Wie kann ich kündigen.
</button>
</h5>
</div>
<div id="collapseThree" class="collapse" aria-labelledby="headingThree" data-parent="#accordion">
<div class="card-body">
Man kann aus dem Abo nicht mehr aussteigen. Bei nicht Zahlung bleibt das Abo trotzdem bestehen und es erhöht
sich einfach monatlich um wenige Euro.
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { QuestionsComponent } from './questions.component';
describe('QuestionsComponent', () => {
let component: QuestionsComponent;
let fixture: ComponentFixture<QuestionsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ QuestionsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(QuestionsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-questions',
templateUrl: './questions.component.html',
styleUrls: ['./questions.component.css']
})
export class QuestionsComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,26 @@
.form-signin {
width: 100%;
max-width: 500px;
padding: 15px;
margin: auto;
}
.form-signin .checkbox {
font-weight: 400;
}
.form-signin .form-floating:focus-within {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}

View File

@ -0,0 +1,39 @@
<div class="form-signin">
<form (ngSubmit)="onSubmit()" style="margin-top: 20%;">
<h1 class="h3 mb-3 fw-normal" style="text-align: center;">Register</h1>
<p style="text-align: center;"><span style="color: #ff7675;">*</span> Symbolizes required fields</p>
<div class="row">
<div class="col-md-6">
<div class="form-floating">
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com" [(ngModel)]="email" name="email">
<label for="floatingInput">Email<span style="color: #ff7675;">*</span></label>
</div>
<div class="form-floating">
<input type="text" class="form-control" id="floatingInput" placeholder="name@example.com" [(ngModel)]="username" name="username">
<label for="floatingInput">Username<span style="color: #ff7675;">*</span></label>
</div>
<div class="form-floating">
<input type="password" class="form-control" id="floatingInput" placeholder="Secure Password" [(ngModel)]="password" name="password">
<label for="floatingInput">Password<span style="color: #ff7675;">*</span></label>
</div>
</div>
<div class="col-md-6">
<div class="form-floating">
<input type="text" class="form-control" id="floatingInput" placeholder="name@example.com" [(ngModel)]="firstname" name="firstname">
<label for="floatingInput">Firstname</label>
</div>
<div class="form-floating">
<input type="text" class="form-control" id="floatingInput" placeholder="name@example.com" [(ngModel)]="lastname" name="lastname">
<label for="floatingInput">Lastname</label>
</div>
<div class="form-floating">
<input type="password" class="form-control" id="floatingInput" placeholder="Secure Password x2" [(ngModel)]="password_verify" name="password_verify">
<label for="floatingInput">Verify Password<span style="color: #ff7675;">*</span></label>
</div>
</div>
</div>
<br>
<button class="w-100 btn btn-lg btn-primary" type="submit">Register now</button>
<a href="/login">Already registered?</a>
</form>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RegisterComponent } from './register.component';
describe('RegisterComponent', () => {
let component: RegisterComponent;
let fixture: ComponentFixture<RegisterComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ RegisterComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(RegisterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,52 @@
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { last } from 'rxjs';
import { AuthService } from '../auth.service';
import { ConfigService } from '../config.service';
@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {
username:string;
password:string;
password_verify:string;
email:string;
firstname = null;
lastname = null;
name = null;
constructor(
private http: HttpClient,
private router: Router,
private config: ConfigService
) { }
ngOnInit(): void { }
onSubmit(){
if(this.password == this.password_verify) {
// TODO check that password matches required complexity
if(this.firstname != null) this.name += this.firstname;
if(this.lastname != null) this.name += this.lastname;
const user = {
username: this.username,
email: this.email,
password: this.password.toString(),
name: this.name
}
// TODO send to auth service to register at the backend
this.http.post<any>(this.config.hostname + '/user/register', user).subscribe(data => {
console.log(data['success']);
this.router.navigate(['/login']);
});
}
}
}

View File

@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RegisterComponent } from './register.component';
import { HttpClient, HttpClientModule, HttpHandler } from '@angular/common/http';
@NgModule({
declarations: [RegisterComponent],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
HttpClientModule
]
})
export class RegisterModule { }

View File

@ -0,0 +1,12 @@
.selector {
border: 1px solid #bdc3c7;
padding: 10px;
transition-duration: 200ms;
border-radius: 5px;
}
.selector:hover {
border: 1px solid #3498db;
}
.selected {
border: 1px solid #3498db;
}

View File

@ -0,0 +1,12 @@
<div class="container">
<div class="row" style="padding: 0;">
<div class="col-1"></div>
<div class="col-10" style="padding:0">
<h2>Proxima Found {{searchAmnt}} Results </h2>
<hr>
<div class="row" #searchList>
</div>
<div class="col-1"></div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SearchPageComponent } from './search-page.component';
describe('SearchPageComponent', () => {
let component: SearchPageComponent;
let fixture: ComponentFixture<SearchPageComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ SearchPageComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(SearchPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,65 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Component, ElementRef, OnInit, Renderer2, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ConfigService } from '../config.service';
@Component({
selector: 'app-search-page',
templateUrl: './search-page.component.html',
styleUrls: ['./search-page.component.css']
})
export class SearchPageComponent implements OnInit {
@ViewChild('searchList')cl:ElementRef;
searchAmnt:number;
constructor(
private http:HttpClient,
private rednerer:Renderer2,
private activatedRoute: ActivatedRoute,
private config: ConfigService) { }
ngOnInit(): void {
const query = {
query: this.activatedRoute.snapshot.params['query']
};
let params = new HttpParams()
.set('query',JSON.stringify(query));
this.http.get<any>(this.config.hostname + '/videos/search', {
params: params
}).subscribe(data => {
console.log(data);
this.searchAmnt = data.length;
for(let i = 0; i < data.length; i++) {
// TODO: construct html for the page to load
// ALSO TODO: determing what data is needed on this exact page
const topDiv:HTMLDivElement = this.rednerer.createElement("div");
const Anchor:HTMLAnchorElement = this.rednerer.createElement("a");
const div:HTMLDivElement = this.rednerer.createElement("div");
const Img:HTMLImageElement = this.rednerer.createElement("img");
const bottomdiv:HTMLDivElement = this.rednerer.createElement("div")
const title: HTMLTitleElement = this.rednerer.createElement("h2");
const titleText = this.rednerer.createText(data[i]["title"])
topDiv.appendChild(Anchor);
topDiv.classList.add("col-4");
Anchor.appendChild(div);
Anchor.href = "/watch/" + data[i]["vid_id"];
div.appendChild(Img);
div.classList.add("card");
div.classList.add("bg-dark");
div.appendChild(bottomdiv);
bottomdiv.appendChild(title);
bottomdiv.classList.add("card-img-overlay");
bottomdiv.style.backgroundColor = "rgba(0, 0, 0, 0.432)";
title.appendChild(titleText);
title.classList.add("card-title");
title.style.color = "white";
Img.classList.add("card-img");
Img.src = "https://proxima-tv.github.io/poster.jpg";
this.cl.nativeElement.prepend(topDiv);
}
});
}
}

View File

@ -0,0 +1,14 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
@NgModule({
declarations: [],
imports: [
CommonModule,
HttpClient
]
})
export class SearchPageModule { }

View File

View File

@ -0,0 +1,8 @@
<div class="input-group">
<div class="form-outline">
<input id="search-input" type="text" id="form1" class="form-control" />
<label class="form-label" for="form1">Find Your Poisen!</label>
</div>
<button id="search-button" type="button" class="btn btn-primary">
</button>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SearchComponent } from './search.component';
describe('SearchComponent', () => {
let component: SearchComponent;
let fixture: ComponentFixture<SearchComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ SearchComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(SearchComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SearchComponent } from './search.component';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@NgModule({
declarations: [SearchComponent],
imports: [
CommonModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule
]
})
export class SearchModule { }

View File

@ -0,0 +1,61 @@
.b-example-divider {
height: 3rem;
background-color: rgba(0, 0, 0, .1);
border: solid rgba(0, 0, 0, .15);
border-width: 1px 0;
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
}
.bi {
vertical-align: -.125em;
fill: currentColor;
}
.feature-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 4rem;
height: 4rem;
margin-bottom: 1rem;
font-size: 2rem;
color: #fff;
border-radius: .75rem;
}
.icon-link {
display: inline-flex;
align-items: center;
}
.icon-link > .bi {
margin-top: .125rem;
margin-left: .125rem;
transition: transform .25s ease-in-out;
fill: currentColor;
}
.icon-link:hover > .bi {
transform: translate(.25rem);
}
.icon-square {
display: inline-flex;
align-items: center;
justify-content: center;
width: 3rem;
height: 3rem;
font-size: 1.5rem;
border-radius: .75rem;
}
.rounded-4 { border-radius: .5rem; }
.rounded-5 { border-radius: 1rem; }
.text-shadow-1 { text-shadow: 0 .125rem .25rem rgba(0, 0, 0, .25); }
.text-shadow-2 { text-shadow: 0 .25rem .5rem rgba(0, 0, 0, .25); }
.text-shadow-3 { text-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .25); }
.card-cover {
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
}

View File

@ -0,0 +1,19 @@
<div class="container" id="featured-3">
<h2 class="pb-2 border-bottom">Columns with icons</h2>
<div class="row">
<div class="feature col">
<div class="feature-icon bg-primary bg-gradient">
<img src="assets/lowcost.png" alt="" width="48" height="48">
</div>
<h2>Mostly free</h2>
<p>Sounds to good to be true? well it is true! Proxima.TV does not lock main content behind paywalls our premium service brings features to enhance Your experience and more special content</p>
</div>
<div class="feature col">
<div class="feature-icon bg-primary bg-gradient">
<img class="bi" src="assets/desktop.png" alt="" width="48" height="48">
</div>
<h2>Watch where you like</h2>
<p>We are always expanding the supported platforms proxima.tv can run on. with our website that was created to work on any devices, we introduced our first step towards true multiplatforming.</p>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ServicePreviewComponent } from './service-preview.component';
describe('ServicePreviewComponent', () => {
let component: ServicePreviewComponent;
let fixture: ComponentFixture<ServicePreviewComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ServicePreviewComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ServicePreviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-service-preview',
templateUrl: './service-preview.component.html',
styleUrls: ['./service-preview.component.css']
})
export class ServicePreviewComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

View File

@ -0,0 +1,81 @@
<div class="container">
<div class="row">
<div class="col-6" style="border-radius: 5px; padding: 5px;">
<div style="padding: 0 5px 0;">
<h1>General Profile Settings</h1>
<div class="mb-3">
<div class="row">
<div class="col-10">
<label for="formFile" class="form-label">Update Profile Picture:</label>
<input class="form-control" type="file" id="formFile">
</div>
<div class="col-1">
<img src="{{profile_pic}}" style="border-radius: 5px;" width="64" alt="profile-picture">
</div>
</div>
</div>
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">Email address:</label>
<input type="email" class="form-control" id="exampleFormControlInput1" value="{{email}}">
</div>
<div class="mb-3">
<label for="exampleFormControlTextarea1" class="form-label">Profile Bio:</label>
<div class="input-group">
<textarea class="form-control" aria-label="With textarea" value="{{profile_bio}}"></textarea>
</div>
<button class="btn btn-success">Save</button></div>
</div>
</div>
<div class="col-6" style="border-radius: 5px; padding: 5px;">
<div style="padding: 0 5px 0;">
<h1>Security Settings</h1>
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">New Password:</label>
<input type="password" class="form-control" id="exampleFormControlInput1">
</div>
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">Confirm New Password:</label>
<input type="password" class="form-control" id="exampleFormControlInput1">
</div>
<hr>
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">Old Password:</label>
<input type="password" class="form-control" id="exampleFormControlInput1">
</div>
<button class="btn btn-success">Save</button>
</div>
</div>
<div class="col-6">
<br>
<h1>Misc Settings:</h1>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="flexCheckIndeterminate">
<label class="form-check-label" for="flexCheckIndeterminate">
Subscribe to Newsletter
</label>
</div>
</div>
<div class="col-6">
<br>
<h1>Privacy Settings:</h1>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="flexCheckIndeterminate">
<label class="form-check-label" for="flexCheckIndeterminate">
Show Profile Public
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="flexCheckIndeterminate">
<label class="form-check-label" for="flexCheckIndeterminate">
Show Stats Public
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="flexCheckIndeterminate">
<label class="form-check-label" for="flexCheckIndeterminate">
Show Watch History Public
</label>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SettingsComponent } from './settings.component';
describe('SettingsComponent', () => {
let component: SettingsComponent;
let fixture: ComponentFixture<SettingsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ SettingsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(SettingsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,50 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { ConfigService } from '../config.service';
import { CookiesService } from '../cookies.service';
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.css']
})
export class SettingsComponent implements OnInit {
username:string;
name: string;
email: string;
profile_bio: string;
profile_pic: string;
constructor(
private cookies: CookiesService,
private http: HttpClient,
private config: ConfigService
) { }
ngOnInit(): void {
let cookie = this.cookies.getCookie('proxima-login-cookie').split(",");
console.log(cookie);
const query = {
email: cookie[1]
};
let params = new HttpParams()
.set('user',JSON.stringify(query));
this.http.get<any>(this.config.hostname + '/user/settings', {
params: params
}).subscribe(data => {
let fetched = data[0];
console.log(fetched);
// TODO: construct html for the page to load
// ALSO TODO: determing what data is needed on this exact page
this.username = fetched["username"];
this.name = fetched["name"];
this.email = fetched["email"];
this.profile_bio = fetched["profile_bio"];
this.profile_pic = fetched["profile_pic"];
});
}
onChange(): void { }
}

View File

@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SettingsComponent } from './settings.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [SettingsComponent],
imports: [
CommonModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule
]
})
export class SettingsModule { }

View File

View File

@ -0,0 +1,15 @@
<div class="container">
<h1>Viewing Stats: </h1>
<div class="row">
<div class="col-md-6" style="padding: 0 2% 0;"> </div>
<div class="col-md-6" style="padding: 0 2% 0;"> </div>
<div class="col-md-6" style="padding: 0 2% 0;">
<br>
<app-history></app-history>
</div>
<div class="col-md-6">
<br>
<app-comments></app-comments>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { StatsComponent } from './stats.component';
describe('StatsComponent', () => {
let component: StatsComponent;
let fixture: ComponentFixture<StatsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ StatsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(StatsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,22 @@
import { Component, OnInit } from '@angular/core';
import { CookiesService } from '../cookies.service';
@Component({
selector: 'app-stats',
templateUrl: './stats.component.html',
styleUrls: ['./stats.component.css']
})
export class StatsComponent implements OnInit {
CookieService: any;
constructor() { }
ngOnInit(): void {
let reload = this.CookieService.get("proxima-login-reload");
if(reload != null) {
this.CookieService.deleteCookie("proxima-login-reload");
document.location.reload();
}
}
}

View File

View File

@ -0,0 +1,33 @@
<div class="container">
<form (ngSubmit)="onSubmit()" enctype="multipart/form-data">
<div class="row">
<div class="col-12">
<h3>Do not Close this Site, during an Upload</h3>
<h6>Status: {{status}}</h6>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" [style.width.%]="progress">{{status}}</div>
</div>
<hr>
</div>
<div class="col-6">
<div class="mb-3">
<label for="vidName" class="form-label">Video Title</label>
<input type="text" class="form-control" id="vidName" placeholder="Videoname..." [(ngModel)]="vidName">
</div>
<div class="mb-3">
<label for="vidfile" class="form-label">The Video File</label>
<input class="form-control" type="file" id="vidfile" (change)="onFileSelected($event)" accept="video/mp4">
</div>
</div>
<div class="col-6">
<img src="" class="img-fluid" alt="Thumbnail Preview">
<div class="mb-3">
<label for="vidThumbnail" class="form-label">Video Thumbnail</label>
<input class="form-control" type="file" id="vidThumbnail" [(ngModel)]="vidThumbnail" accept="image/*">
</div>
</div>
</div>
<button class="w-100 btn btn-lg btn-primary" type="submit">Submit</button>
</form>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UploadsComponent } from './uploads.component';
describe('UploadsComponent', () => {
let component: UploadsComponent;
let fixture: ComponentFixture<UploadsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ UploadsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(UploadsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,68 @@
import { HttpClient, HttpEvent, HttpEventType } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { catchError, Observable } from 'rxjs';
import { ConfigService } from '../config.service';
import { CookiesService } from '../cookies.service';
@Component({
selector: 'app-uploads',
templateUrl: './uploads.component.html',
styleUrls: ['./uploads.component.css']
})
export class UploadsComponent implements OnInit {
public vidName: any;
public vidFile: File;
public vidThumbnail: File;
public progress: number = 0;
public status: string = "idle";
constructor(
private http: HttpClient,
private config: ConfigService,
private cookies: CookiesService) { }
ngOnInit(): void {
}
onSubmit():void {
const userCookie = this.cookies.getCookie('proxima-login-cookie');
const formData = new FormData();
formData.append("title", this.vidName);
formData.append("file", this.vidFile);
formData.append("thumbnail", this.vidThumbnail);
formData.append("creator", this.cookies.getCookie('proxima-login-cookie').split(',')[2])
console.log("sending Data")
this.http.post<any>(this.config.hostname + '/videos/upload', formData, {
reportProgress: true,
observe: 'events',
}).subscribe((event: HttpEvent<any>) => {
switch (event.type) {
case HttpEventType.Sent:
console.log('Request has been made!');
break;
case HttpEventType.ResponseHeader:
console.log('Response header has been received!');
break;
case HttpEventType.UploadProgress:
var eventTotal = event.total ? event.total : 0;
this.progress = Math.round(event.loaded / eventTotal * 100);
this.status = `Uploaded! ${this.progress}%`;
console.log(`Uploaded! ${this.progress}%`);
break;
case HttpEventType.Response:
console.log('Video Upload Successfully!', event.body);
this.status = 'Video Upload Successfully!';
setTimeout(() => {
this.progress = 0;
this.status = "idle";
}, 1500);
break;
}
});
}
onFileSelected(event):void {
this.vidFile = event.target.files[0];
}
}

Some files were not shown because too many files have changed in this diff Show More