This commit is contained in:
2024-02-19 20:55:35 +01:00
22 changed files with 453 additions and 162 deletions

View File

@ -1,21 +1,40 @@
<p>credits works!</p>
<div class="flex flex-col items-center justify-center min-h-fit p-4 lg:p-28">
<div class="flex items-center justify-center mb-3">
<a href="/" class="flex items-center justify-center">
<img src="./assets/cloud-solid.svg" class="mr-3 w-24 animate-bounce ease-out" alt="SharePulse Logo" />
<span class="self-center text-4xl font-semibold whitespace-nowrap">SharePulse</span>
</a>
</div>
<h2 class="text-2xl font-semibold text-gray-800 mb-10 text-center">
Upload a file. Share the URL/link. Download the file. Simple as that.
</h2>
<div class="space-y-4 text-xl mb-20">
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-4">
<h3 class="font-semibold text-gray-800 sm:col-span-2 md:text-right">Developer:</h3>
<p class="text-gray-800 sm:col-span-2 sm:text-left">Walzen665</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-4">
<h3 class="font-semibold text-gray-800 sm:col-span-2 md:text-right">Version:</h3>
<p class="text-gray-800 sm:col-span-2 sm:text-left">1.0.0</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-4">
<h3 class="font-semibold text-gray-800 sm:col-span-2 md:text-right">API-Status:</h3>
<p class="sm:col-span-2 sm:text-left text-green-600">online</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-4">
<h3 class=" font-semibold text-gray-800 sm:col-span-2 md:text-right">Libraries:</h3>
<p class="text-gray-800 sm:col-span-2 sm:text-left">
<a href="https://fontawesome.com/" class="text-indigo-600 hover:text-indigo-800">Fontawesome</a>,
<a href="https://tailwindcss.com/" class="text-indigo-600 hover:text-indigo-800">TailwindCSS</a>,
<a href="https://axios-http.com/" class="text-indigo-600 hover:text-indigo-800">AXIOS http</a>,
<a href="https://www.npmjs.com/package/tailwindcss-animate" class="text-indigo-600 hover:text-indigo-800">TailwindCSS Animations</a>
</p>
</div>
</div>
<h2 class="text-2xl font-semibold text-gray-800 mb-4">
Used media
</h2>
<ul class="list-disc pl-5 space-y-2">
<li>
<p class="font-medium text-gray-700">Icons used:</p>
<a href="https://fontawesome.com/" class="text-blue-500 hover:text-blue-600 transition duration-300 ease-in-out">Fontawesome</a>
</li>
<li>
<p class="font-medium text-gray-700">HTML, CSS, JS Libraries used:</p>
<a href="https://tailwindcss.com/" class="text-blue-500 hover:text-blue-600 transition duration-300 ease-in-out">TailwindCSS</a>,
<a href="https://axios-http.com/" class="text-blue-500 hover:text-blue-600 transition duration-300 ease-in-out">AXIOS http</a>,
<a href="https://www.npmjs.com/package/tailwindcss-animate" class="text-blue-500 hover:text-blue-600 transition duration-300 ease-in-out">TailwindCSS Animations</a>
</li>
<li>
<p class="font-medium text-gray-700">App Icon by flaticon.com</p>
<a href="https://www.flaticon.com/de/autoren/najmunnahar" class="text-blue-500 hover:text-blue-600 transition duration-300 ease-in-out">NajmunNahar</a>
</li>
</ul>
<p>
<span class="text-indigo-600 cursor-pointer" (click)="openPrivacyPolicyModal()">Privacy Policy</span> |
<span class="text-indigo-600 cursor-pointer" (click)="openTermsOfUseModal()">Terms of Use</span>
</p>
</div>

View File

@ -1,12 +1,26 @@
import { Component } from '@angular/core';
import {RouterLink} from "@angular/router";
import {LegalService} from "../../service/legalService";
@Component({
selector: 'app-credits',
standalone: true,
imports: [],
imports: [
RouterLink
],
templateUrl: './credits.component.html',
styleUrl: './credits.component.scss'
})
export class CreditsComponent {
constructor(private legalService: LegalService) {
}
openPrivacyPolicyModal() {
this.legalService.openPrivacyPolicy();
}
openTermsOfUseModal() {
this.legalService.openTermsOfUse();
}
}

View File

@ -4,7 +4,7 @@ import {DevelopmentStore} from "../../store/DevelopmentStore";
import {FormsModule} from "@angular/forms";
import {DecimalPipe, NgClass, NgIf} from "@angular/common";
import funfacts from "../../assets/funfacts";
import {RouterLink} from "@angular/router";
import {ActivatedRoute, RouterLink} from "@angular/router";
@Component({
selector: 'app-download',
@ -24,7 +24,7 @@ export class DownloadComponent {
@ViewChild('download_not_possible') download_not_possible: ElementRef<HTMLDialogElement> | undefined;
@ViewChild('file_not_found_modal') file_not_found_modal: ElementRef<HTMLDialogElement> | undefined;
inputFileId: string = "2402183";
inputFileId: string = "";
fileId: string = "";
filePassword: string = "";
fileName: string = "";
@ -34,14 +34,28 @@ export class DownloadComponent {
fileDownloadFinished: boolean = false;
waitingForPassword: boolean = false;
downloadProgress: number = 0;
targetUploadProgress: number = 0;
downloadDuration: string = "";
passwordWrong: boolean = false;
funfact: string = "";
constructor(private developmentStore: DevelopmentStore) {
constructor(private developmentStore: DevelopmentStore, private activatedRoute: ActivatedRoute) {
this.funfact = funfacts[Math.floor(Math.random() * funfacts.length)];
this.activatedRoute.queryParams.subscribe(params => {
const fileId = params['fileId'];
const password = params['password'];
if(password) {
this.filePassword = password;
}
if(fileId) {
this.inputFileId = fileId;
this.requestDownload();
}
});
this.speedTest();
}
@ -70,6 +84,11 @@ export class DownloadComponent {
return;
}
else if(this.downloadInfo?.passwordProtected) {
if(this.filePassword) {
console.log("Requesting download with password");
this.downloadFile();
return;
}
this.waitingForPassword = true;
console.log("Password protected");
}
@ -137,8 +156,8 @@ export class DownloadComponent {
// Calculate the percentage of download completed
if(progressEvent.total) {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
this.downloadProgress = percentCompleted;
console.log(percentCompleted + '%'); // Log the percentage or update any progress UI component
this.targetUploadProgress = percentCompleted;
this.smoothProgressUpdate();
}
}
})
@ -183,6 +202,16 @@ export class DownloadComponent {
private wrongPassword() {
this.passwordWrong = true;
}
smoothProgressUpdate() {
if (this.downloadProgress < this.targetUploadProgress) {
this.downloadProgress += 0.01 * (this.targetUploadProgress - this.downloadProgress);
requestAnimationFrame(this.smoothProgressUpdate.bind(this));
} else if (this.downloadProgress > this.targetUploadProgress) {
// Handle overshoot
this.downloadProgress = this.targetUploadProgress;
}
}
}
interface DownloadInfo {
downloadable: boolean;

View File

@ -25,72 +25,11 @@
<p class="text-gray-600 text-center mb-4">We prioritize data security and privacy consequently.
Files uploaded by our clients are securely stored on our servers for a maximum duration of one day,
after which they are permanently deleted to guarantee the highest level of confidentiality and data protection. Read more in our
<span class="text-indigo-600 cursor-pointer" (click)="openPrivacyPolicy()">Privacy Policy</span> note.
By using SharePulse, you agree to the <span class="text-indigo-600 cursor-pointer" (click)="openTermsOfUse()">Terms of Use</span>.</p>
<span class="text-indigo-600 cursor-pointer" (click)="openPrivacyPolicyModal()">Privacy Policy</span> note.
By using SharePulse, you agree to the <span class="text-indigo-600 cursor-pointer" (click)="openTermsOfUseModal()">Terms of Use</span>.</p>
</div>
</div>
<dialog #privacy_policy_modal class="modal">
<div class="modal-box w-11/12 max-w-5xl">
<h3 class="font-bold text-lg">SharePulse™ Privacy Policy</h3>
<div>
<div class="mx-auto my-6">
<ol class="list-decimal">
<li class="ml-4 mb-2 text-gray-800 font-semibold">Uploaded files are stored on a secure server.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Files are stored for a maximum of 24 hours.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Sharepulse tracks your IP address when uploading files.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Sharepulse may track your IP address when downloading files.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Sharepulse does not track you when accessing the website.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Personal information collected by Sharepulse is used solely for data protection and is not processed.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Sharepulse will not sell, rent, or share personal information with third parties without user consent, except as required by law.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Users have the right to request the deletion of their data from Sharepulse's servers at any time.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Sharepulse does not store any cookies on your device.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Operators do not view or manipulate uploaded files.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Users are encouraged to review the privacy policy periodically for any changes or updates.</li>
</ol>
</div>
<form method="dialog">
<button class="btn">Okay</button>
</form>
</div>
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form>
</div>
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>
<dialog #terms_of_use_modal class="modal">
<div class="modal-box w-11/12 max-w-5xl">
<h3 class="font-bold text-lg">SharePulse™ Terms of Use</h3>
<div>
<div class="mx-auto my-6">
<ol class="list-decimal">
<li class="ml-4 mb-2 text-gray-800 font-semibold">Users must not upload files that contain malware, illegal content, or violate copyright laws.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Sharepulse is not responsible for the content of the files shared through its service.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">By using Sharepulse, users agree not to attempt to breach the security of the service.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Sharepulse reserves the right to remove any files or suspend users that violate these terms without notice.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">The service is provided "as is" without warranty of any kind, express or implied.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Users agree to indemnify and hold harmless Sharepulse from any claims resulting from the use of the service.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Sharepulse reserves the right to modify these terms at any time. Continued use of the service after such changes constitutes acceptance of the new terms.</li>
</ol>
</div>
<form method="dialog">
<button class="btn">Okay</button>
</form>
</div>
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form>
</div>
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>
<!-- Invisible SVGs to prevent lazy loading -->
<div class="invisible h-0 w-0">
<img src="./assets/cloud-arrow-up-solid.svg">

View File

@ -1,6 +1,7 @@
import {Component, ElementRef, ViewChild} from '@angular/core';
import {RouterLink} from "@angular/router";
import {FormsModule} from "@angular/forms";
import {LegalService} from "../../service/legalService";
@Component({
selector: 'app-home',
@ -13,15 +14,14 @@ import {FormsModule} from "@angular/forms";
styleUrl: './home.component.scss'
})
export class HomeComponent {
@ViewChild('privacy_policy_modal') privacy_policy_modal: ElementRef<HTMLDialogElement> | undefined;
@ViewChild('terms_of_use_modal') terms_of_use_modal: ElementRef<HTMLDialogElement> | undefined;
openPrivacyPolicy() {
this.privacy_policy_modal?.nativeElement.showModal();
constructor(private legalService: LegalService) {
}
openTermsOfUse() {
this.terms_of_use_modal?.nativeElement.showModal();
openPrivacyPolicyModal() {
this.legalService.openPrivacyPolicy();
}
openTermsOfUseModal() {
this.legalService.openTermsOfUse();
}
}

View File

@ -6,7 +6,7 @@
<span class="self-center text-xl font-semibold whitespace-nowrap">SharePulse</span>
</a>
<div class="flex items-center lg:order-2">
<a routerLink="/credits" class="text-gray-800 hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-4 lg:px-5 py-2 lg:py-2.5 mr-2">Administration</a>
<a routerLink="/credits" class="text-gray-800 hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-4 lg:px-5 py-2 lg:py-2.5 mr-2"><!--Administration-->About</a>
<button (click)="toggleMenu()" type="button" class="inline-flex items-center p-2 ml-1 text-sm text-gray-500 rounded-lg lg:hidden hover:bg-gray-100 " aria-controls="mobile-menu-2" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path></svg>
@ -26,3 +26,65 @@
</div>
</nav>
</header>
<dialog #privacy_policy_modal class="modal">
<div class="modal-box w-11/12 max-w-5xl">
<h3 class="font-bold text-lg">SharePulse™ Privacy Policy</h3>
<div>
<div class="mx-auto my-6">
<ol class="list-decimal">
<li class="ml-4 mb-2 text-gray-800 font-semibold">Uploaded files are stored on a secure server.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Files are stored for a maximum of 24 hours.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">SharePulse tracks your IP address when uploading files. This serves as a method of identification, allowing you to check the status of your upload.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">SharePulse may track your IP address when downloading files.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">SharePulse does not track you when accessing the website.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Personal information collected by SharePulse is used solely for data protection and is not processed.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">SharePulse will not sell, rent, or share personal information with third parties without user consent, except as required by law.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Users have the right to request the deletion of their data from SharePulse's servers at any time.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">SharePulse does not store any cookies on your device.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Operators do not view or manipulate uploaded files.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Users are encouraged to review the privacy policy periodically for any changes or updates.</li>
</ol>
</div>
<form method="dialog">
<button class="btn">Okay</button>
</form>
</div>
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form>
</div>
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>
<dialog #terms_of_use_modal class="modal">
<div class="modal-box w-11/12 max-w-5xl">
<h3 class="font-bold text-lg">SharePulse™ Terms of Use</h3>
<div>
<div class="mx-auto my-6">
<ol class="list-decimal">
<li class="ml-4 mb-2 text-gray-800 font-semibold">Users must not upload files that contain malware, illegal content, or violate copyright laws.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">SharePulse is not responsible for the content of the files shared through its service.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">By using SharePulse, users agree not to attempt to breach the security of the service.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">SharePulse reserves the right to remove any files or suspend users that violate these terms without notice.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">The service is provided "as is" without warranty of any kind, express or implied.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">Users agree to indemnify and hold harmless SharePulse from any claims resulting from the use of the service.</li>
<li class="ml-4 mb-2 text-gray-800 font-semibold">SharePulse reserves the right to modify these terms at any time. Continued use of the service after such changes constitutes acceptance of the new terms.</li>
</ol>
</div>
<form method="dialog">
<button class="btn">Okay</button>
</form>
</div>
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form>
</div>
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>

View File

@ -1,21 +1,46 @@
import { Component } from '@angular/core';
import {Component, ElementRef, ViewChild} from '@angular/core';
import {RouterLink} from "@angular/router";
import {NgClass} from "@angular/common";
import {FormsModule} from "@angular/forms";
import {LegalService} from "../../service/legalService";
@Component({
selector: 'app-navbar',
standalone: true,
imports: [
RouterLink,
NgClass
],
imports: [
RouterLink,
NgClass,
FormsModule
],
templateUrl: './navbar.component.html',
styleUrl: './navbar.component.scss'
})
export class NavbarComponent {
@ViewChild('privacy_policy_modal') privacy_policy_modal: ElementRef<HTMLDialogElement> | undefined;
@ViewChild('terms_of_use_modal') terms_of_use_modal: ElementRef<HTMLDialogElement> | undefined;
isMenuOpen = false;
constructor(private legalService: LegalService) {
this.legalService.openModal$.subscribe((modalId) => {
if (modalId === 'privacyPolicy') {
this.openPrivacyPolicy();
} else if (modalId === 'termsOfUse') {
this.openTermsOfUse();
}
});
}
toggleMenu(): void {
this.isMenuOpen = !this.isMenuOpen;
}
openPrivacyPolicy() {
this.privacy_policy_modal?.nativeElement.showModal();
}
openTermsOfUse() {
this.terms_of_use_modal?.nativeElement.showModal();
}
}

View File

@ -28,17 +28,18 @@
<div class="w-full mb-10">
<label class="block text-gray-700 text-l font-bold mb-4">Options</label>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="flex items-center">
<input id="shortStorage" [(ngModel)]="shortStorage" type="checkbox" class="toggle" checked />
<label for="shortStorage" class="ml-2 text-gray-700">Store for only one hour</label>
<div class="flex items-center" >
<input id="shortStorage" [(ngModel)]="shortStorage" type="checkbox" class="toggle" [disabled]="true"/>
<label for="shortStorage" class="ml-2 text-gray-700 tooltip" data-tip="This feature will be available with the next update!">Store for only one hour</label>
</div>
<div class="flex items-center">
<input id="singleDownload" [(ngModel)]="singleDownload" type="checkbox" class="toggle" />
<label for="singleDownload" class="ml-2 text-gray-700">Allow only one download</label>
<label for="singleDownload" class="ml-2 text-gray-700 tooltip" data-tip="If enabled, the uploaded file can only be downloaded once.">Allow only one download</label>
</div>
<div class="flex items-center">
<input id="passwordProtected" [(ngModel)]="passwordProtected" type="checkbox" class="toggle" />
<label for="passwordProtected" class="ml-2 text-gray-700">Protect download with password</label>
<label for="passwordProtected" class="ml-2 text-gray-700 tooltip"
data-tip="The password will be generated by the server and is displayed after the upload is finished.">Protect download with password</label>
</div>
</div>
</div>

View File

@ -115,14 +115,19 @@ export class UploadComponent {
buildFileUrls(fileDetails: FileDetails) {
const baseUrl = this.developmentStore.getBaseUrl();
const fileId = fileDetails.fileId;
const downloadUrl = `${baseUrl}download?fileId=${fileId}`;
const deleteUrl = `${baseUrl}api/v1/deletefile?fileId=${fileId}`;
const statusUrl = `${baseUrl}status?fileId=${fileId}`;
let passwordUrlPart = '';
if(fileDetails.passwordProtected) {
passwordUrlPart = `&password=${fileDetails.password}`;
}
const downloadUrl = `${baseUrl}download?fileId=${fileId}${passwordUrlPart}`;
const deleteUrl = `${baseUrl}api/v1/deletefile?fileId=${fileId}${passwordUrlPart}`;
const statusUrl = `${baseUrl}status?fileId=${fileId}${passwordUrlPart}`;
return {
downloadUrl,
statusUrl,
deleteUrl,
}; }
};
}
buildFormDataObject(): FormData {
const formData = new FormData();

View File

@ -0,0 +1,23 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
/**
* Service to open the privacy policy and terms of use modals
* The modals are controlled by the navbar component
*/
export class LegalService {
private openModalSource = new Subject<string>();
openModal$ = this.openModalSource.asObservable();
openPrivacyPolicy() {
this.openModalSource.next('privacyPolicy');
}
openTermsOfUse() {
this.openModalSource.next('termsOfUse');
}
}