finished files page
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="WebDav.Client" Version="2.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
namespace BetterIServ.Backend.Controllers;
|
||||
|
||||
[ApiController]
|
||||
public class HelperController : Controller {
|
||||
public class HelperController : ControllerBase {
|
||||
|
||||
[HttpPost("/login")]
|
||||
public async Task<ActionResult<string>> Login([FromForm] string email, [FromForm] string password) {
|
||||
@@ -34,7 +34,7 @@ public class HelperController : Controller {
|
||||
|
||||
return Ok(part.Replace("IServAuthSession=", ""));
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Exception) {
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
115
BetterIServ.Backend/Controllers/WebDavController.cs
Normal file
115
BetterIServ.Backend/Controllers/WebDavController.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System.Net;
|
||||
using BetterIServ.Backend.Entities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WebDav;
|
||||
|
||||
namespace BetterIServ.Backend.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("webdav")]
|
||||
public class WebDavController : ControllerBase {
|
||||
|
||||
[HttpPost("content")]
|
||||
public async Task<ActionResult<DirectoryContent[]>> GetDirContent([FromBody] Credentials credentials, [FromQuery] string dir) {
|
||||
var baseAddress = new Uri($"https://webdav.{credentials.Domain}");
|
||||
using var client = new WebDavClient(new WebDavClientParams {
|
||||
BaseAddress = baseAddress,
|
||||
Credentials = new NetworkCredential(credentials.Username, credentials.Password)
|
||||
});
|
||||
|
||||
var result = await client.Propfind(baseAddress + dir);
|
||||
if (!result.IsSuccessful) return NotFound(result.Description);
|
||||
|
||||
var contents = new List<DirectoryContent>();
|
||||
foreach (var resource in result.Resources) {
|
||||
var name = resource.Uri.Split("/")[^1];
|
||||
if (resource.Uri.EndsWith("/"))
|
||||
name = resource.Uri.Split("/")[^2];
|
||||
|
||||
var content = new DirectoryContent {
|
||||
Url = resource.Uri,
|
||||
LastModified = resource.LastModifiedDate ?? DateTime.Now,
|
||||
Size = resource.ContentLength ?? 0,
|
||||
Type = resource.IsCollection ? "dir" : "file",
|
||||
Name = name
|
||||
};
|
||||
contents.Add(content);
|
||||
}
|
||||
contents.RemoveAt(0);
|
||||
|
||||
return contents.OrderBy(item => item.Type).ToArray();
|
||||
}
|
||||
|
||||
[HttpPost("download")]
|
||||
public async Task<FileStreamResult> DonwloadFile([FromBody] Credentials credentials, [FromQuery] string url) {
|
||||
var baseAddress = new Uri($"https://webdav.{credentials.Domain}");
|
||||
using var client = new WebDavClient(new WebDavClientParams {
|
||||
BaseAddress = baseAddress,
|
||||
Credentials = new NetworkCredential(credentials.Username, credentials.Password)
|
||||
});
|
||||
|
||||
var file = await client.GetRawFile(new Uri(baseAddress + url));
|
||||
if (!file.IsSuccessful) {
|
||||
Response.StatusCode = StatusCodes.Status404NotFound;
|
||||
return new FileStreamResult(Stream.Null, "");
|
||||
}
|
||||
|
||||
var split = url.Split("/");
|
||||
return new FileStreamResult(file.Stream, "application/octet-stream") {
|
||||
FileDownloadName = split[^1]
|
||||
};
|
||||
}
|
||||
|
||||
[HttpPost("delete")]
|
||||
public async Task<IActionResult> DeleteElement([FromBody] Credentials credentials, [FromQuery] string url) {
|
||||
var baseAddress = new Uri($"https://webdav.{credentials.Domain}");
|
||||
using var client = new WebDavClient(new WebDavClientParams {
|
||||
BaseAddress = baseAddress,
|
||||
Credentials = new NetworkCredential(credentials.Username, credentials.Password)
|
||||
});
|
||||
|
||||
var result = await client.Delete(new Uri(baseAddress + url));
|
||||
if (result.IsSuccessful) return Ok();
|
||||
return BadRequest(result.Description);
|
||||
}
|
||||
|
||||
[HttpPost("upload")]
|
||||
public async Task<IActionResult> UploadFile([FromQuery] string url, [FromForm] string domain, [FromForm] string username, [FromForm] string password) {
|
||||
var baseAddress = new Uri($"https://webdav.{domain}");
|
||||
using var client = new WebDavClient(new WebDavClientParams {
|
||||
BaseAddress = baseAddress,
|
||||
Credentials = new NetworkCredential(username, password)
|
||||
});
|
||||
|
||||
var result = await client.PutFile(new Uri(baseAddress + url), Request.Form.Files[0].OpenReadStream());
|
||||
if (result.IsSuccessful) return Ok();
|
||||
return BadRequest(result.Description);
|
||||
}
|
||||
|
||||
[HttpPost("create")]
|
||||
public async Task<IActionResult> CreateFolder([FromBody] Credentials credentials, [FromQuery] string url) {
|
||||
var baseAddress = new Uri($"https://webdav.{credentials.Domain}");
|
||||
using var client = new WebDavClient(new WebDavClientParams {
|
||||
BaseAddress = baseAddress,
|
||||
Credentials = new NetworkCredential(credentials.Username, credentials.Password)
|
||||
});
|
||||
|
||||
var result = await client.Mkcol(new Uri(baseAddress + url));
|
||||
if (result.IsSuccessful) return Ok();
|
||||
return BadRequest(result.Description);
|
||||
}
|
||||
|
||||
[HttpPost("move")]
|
||||
public async Task<IActionResult> MoveElement([FromBody] Credentials credentials, [FromQuery] string url, [FromQuery] string newUrl) {
|
||||
var baseAddress = new Uri($"https://webdav.{credentials.Domain}");
|
||||
using var client = new WebDavClient(new WebDavClientParams {
|
||||
BaseAddress = baseAddress,
|
||||
Credentials = new NetworkCredential(credentials.Username, credentials.Password)
|
||||
});
|
||||
|
||||
var result = await client.Move(new Uri(baseAddress + url), new Uri(baseAddress + newUrl));
|
||||
if (result.IsSuccessful) return Ok();
|
||||
return BadRequest(result.Description);
|
||||
}
|
||||
|
||||
}
|
||||
7
BetterIServ.Backend/Entities/Credentials.cs
Normal file
7
BetterIServ.Backend/Entities/Credentials.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace BetterIServ.Backend.Entities;
|
||||
|
||||
public struct Credentials {
|
||||
public string Domain { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
9
BetterIServ.Backend/Entities/DirectoryContent.cs
Normal file
9
BetterIServ.Backend/Entities/DirectoryContent.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace BetterIServ.Backend.Entities;
|
||||
|
||||
public struct DirectoryContent {
|
||||
public string Url { get; set; }
|
||||
public string Name { get; set; }
|
||||
public DateTime LastModified { get; set; }
|
||||
public string Type { get; set; }
|
||||
public long Size { get; set; }
|
||||
}
|
||||
@@ -20,6 +20,8 @@ if (app.Environment.IsDevelopment()) {
|
||||
app.UseCors(options => {
|
||||
options.WithOrigins("http://localhost:8100");
|
||||
options.AllowCredentials();
|
||||
options.AllowAnyHeader();
|
||||
options.AllowAnyMethod();
|
||||
});
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
42
BetterIServ.Mobile/package-lock.json
generated
42
BetterIServ.Mobile/package-lock.json
generated
@@ -14,12 +14,15 @@
|
||||
"@angular/platform-browser": "^15.0.0",
|
||||
"@angular/platform-browser-dynamic": "^15.0.0",
|
||||
"@angular/router": "^15.0.0",
|
||||
"@awesome-cordova-plugins/file": "^6.3.0",
|
||||
"@capacitor/app": "4.1.1",
|
||||
"@capacitor/core": "4.7.3",
|
||||
"@capacitor/haptics": "4.1.0",
|
||||
"@capacitor/keyboard": "4.1.1",
|
||||
"@capacitor/status-bar": "4.1.1",
|
||||
"@ionic/angular": "^7.0.0",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"file-saver": "^2.0.5",
|
||||
"ionicons": "^7.0.0",
|
||||
"rxjs": "~7.5.0",
|
||||
"tslib": "^2.3.0",
|
||||
@@ -692,6 +695,30 @@
|
||||
"integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@awesome-cordova-plugins/core": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@awesome-cordova-plugins/core/-/core-6.3.0.tgz",
|
||||
"integrity": "sha512-MkcWO8akZLHa2RSJEPf76Y3P9wPqh5oXE8YCzn2vnYYeNyYWYnka2pHFsgUdbXJNiS+YeveUzvw+Isweg+wynA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/cordova": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rxjs": "^5.5.0 || ^6.5.0 || ^7.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@awesome-cordova-plugins/file": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@awesome-cordova-plugins/file/-/file-6.3.0.tgz",
|
||||
"integrity": "sha512-w2S/X/pr0Edl8+O/ndIIlnikwkD1XEMM/8TQFp/AI1riqJFyPtYNgnU54iRjagIRJE+GRyydaUnQXp5DVn9Htg==",
|
||||
"dependencies": {
|
||||
"@types/cordova": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@awesome-cordova-plugins/core": "^6.0.1",
|
||||
"rxjs": "^5.5.0 || ^6.5.0 || ^7.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.21.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
|
||||
@@ -3598,6 +3625,11 @@
|
||||
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/cordova": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-11.0.0.tgz",
|
||||
"integrity": "sha512-AtBm1IAqqXsXszJe6XxuA2iXLhraNCj25p/FHRyikPeW0Z3YfgM6qzWb+VJglJTmZc5lqRNy84cYM/sQI5v6Vw=="
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
|
||||
@@ -3656,6 +3688,11 @@
|
||||
"@types/range-parser": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ=="
|
||||
},
|
||||
"node_modules/@types/fs-extra": {
|
||||
"version": "8.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz",
|
||||
@@ -7306,6 +7343,11 @@
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
"@angular/platform-browser": "^15.0.0",
|
||||
"@angular/platform-browser-dynamic": "^15.0.0",
|
||||
"@angular/router": "^15.0.0",
|
||||
"@awesome-cordova-plugins/file": "^6.3.0",
|
||||
"@capacitor/app": "4.1.1",
|
||||
"@capacitor/core": "4.7.3",
|
||||
"@capacitor/haptics": "4.1.0",
|
||||
"@capacitor/keyboard": "4.1.1",
|
||||
"@capacitor/status-bar": "4.1.1",
|
||||
"@ionic/angular": "^7.0.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"ionicons": "^7.0.0",
|
||||
"rxjs": "~7.5.0",
|
||||
"tslib": "^2.3.0",
|
||||
@@ -46,6 +48,7 @@
|
||||
"@ionic/angular-toolkit": "^9.0.0",
|
||||
"@types/jasmine": "~4.0.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@typescript-eslint/eslint-plugin": "5.3.0",
|
||||
"@typescript-eslint/parser": "5.3.0",
|
||||
"eslint": "^7.6.0",
|
||||
|
||||
@@ -9,7 +9,7 @@ import {firstValueFrom} from "rxjs";
|
||||
export class IServService {
|
||||
|
||||
public userdata?: Userdata;
|
||||
private backend: string = "http://localhost:5273";
|
||||
public backend: string = "http://localhost:5273";
|
||||
|
||||
constructor(private client: HttpClient) {
|
||||
const data = localStorage.getItem("userdata");
|
||||
52
BetterIServ.Mobile/src/app/api/webdav.service.ts
Normal file
52
BetterIServ.Mobile/src/app/api/webdav.service.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {IServService} from "./iserv.service";
|
||||
import {HttpClient, HttpEvent} from "@angular/common/http";
|
||||
import {DirectoryContent} from "../entities/directoryContent";
|
||||
import {firstValueFrom, Observable} from "rxjs";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class WebdavService {
|
||||
|
||||
constructor(private iserv: IServService, private client: HttpClient) {}
|
||||
|
||||
public async getDirectory(path: string): Promise<DirectoryContent[]> {
|
||||
const contents = await firstValueFrom(this.client.post<DirectoryContent[]>(this.iserv.backend + "/webdav/content?dir=" + path, this.iserv.userdata));
|
||||
|
||||
for (let content of contents) {
|
||||
content.name = decodeURIComponent(content.name);
|
||||
content.url = decodeURI(content.url);
|
||||
content.lastModified = new Date(content.lastModified);
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
public downloadFile(url: string): Observable<HttpEvent<Blob>> {
|
||||
return this.client.post(this.iserv.backend + "/webdav/download?url=" + url, this.iserv.userdata, {responseType: "blob", reportProgress: true, observe: "events"});
|
||||
}
|
||||
|
||||
public async delete(url: string) {
|
||||
await firstValueFrom(this.client.post(this.iserv.backend + "/webdav/delete?url=" + url, this.iserv.userdata));
|
||||
}
|
||||
|
||||
public uploadFile(url: string, file: File): Observable<HttpEvent<any>> {
|
||||
const form = new FormData();
|
||||
form.append('username', this.iserv.userdata.username);
|
||||
form.append('password', this.iserv.userdata.password);
|
||||
form.append('domain', this.iserv.userdata.domain);
|
||||
form.append('file', file);
|
||||
|
||||
return this.client.post(this.iserv.backend + "/webdav/upload?url=" + url, form, {reportProgress: true, observe: "events"});
|
||||
}
|
||||
|
||||
public async createFolder(url: string) {
|
||||
await firstValueFrom(this.client.post(this.iserv.backend + "/webdav/create/?url=" + url, this.iserv.userdata));
|
||||
}
|
||||
|
||||
public async moveElement(url: string, newUrl: string) {
|
||||
await firstValueFrom(this.client.post(this.iserv.backend + `/webdav/move/?url=${url}&newUrl=${newUrl}`, this.iserv.userdata));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<ion-app>
|
||||
<ion-split-pane contentId="main-content">
|
||||
<ion-menu contentId="main-content" type="overlay">
|
||||
<ion-menu contentId="main-content" type="overlay" *ngIf="router.url != '/login'">
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-list-header>BetterIServ</ion-list-header>
|
||||
@@ -14,7 +14,7 @@
|
||||
</ion-menu-toggle>
|
||||
|
||||
<ion-menu-toggle auto-hide="false">
|
||||
<ion-item lines="none" detail="false" (click)="logout()">
|
||||
<ion-item lines="none" detail="false" routerDirection="root" routerLinkActive="selected" [routerLink]="'logout'" (click)="logout()">
|
||||
<ion-icon aria-hidden="true" slot="start" ios="log-out-outline" md="log-out-sharp"></ion-icon>
|
||||
<ion-label>Ausloggen</ion-label>
|
||||
</ion-item>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { Component } from '@angular/core';
|
||||
import {Router, RouterLink, RouterLinkActive} from '@angular/router';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
import {IServService} from "./Api/iserv.service";
|
||||
import {IServService} from "./api/iserv.service";
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: 'app.component.html',
|
||||
@@ -22,7 +22,7 @@ export class AppComponent {
|
||||
];
|
||||
public email = "leon.hoppe@hgbp.de";
|
||||
|
||||
constructor(private router: Router, public iserv: IServService) {
|
||||
constructor(public router: Router, public iserv: IServService) {
|
||||
if (localStorage.getItem("userdata") == null) {
|
||||
this.router.navigate(["login"]);
|
||||
}
|
||||
|
||||
@@ -8,10 +8,14 @@ export const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'home',
|
||||
loadComponent: () => import('./home/home.page').then( m => m.HomePage)
|
||||
loadComponent: () => import('./pages/home/home.page').then(m => m.HomePage)
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
loadComponent: () => import('./login/login.page').then( m => m.LoginPage)
|
||||
loadComponent: () => import('./pages/login/login.page').then(m => m.LoginPage)
|
||||
},
|
||||
{
|
||||
path: 'files',
|
||||
loadComponent: () => import('./pages/files/files.page').then( m => m.FilesPage)
|
||||
},
|
||||
];
|
||||
|
||||
7
BetterIServ.Mobile/src/app/entities/directoryContent.ts
Normal file
7
BetterIServ.Mobile/src/app/entities/directoryContent.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface DirectoryContent {
|
||||
url: string,
|
||||
name: string,
|
||||
lastModified: Date,
|
||||
type: string,
|
||||
size: number
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
ion-menu-button {
|
||||
color: var(--ion-color-primary);
|
||||
}
|
||||
|
||||
#container {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
#container strong {
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
#container p {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#container a {
|
||||
text-decoration: none;
|
||||
}
|
||||
95
BetterIServ.Mobile/src/app/pages/files/files.page.html
Normal file
95
BetterIServ.Mobile/src/app/pages/files/files.page.html
Normal file
@@ -0,0 +1,95 @@
|
||||
<ion-header [translucent]="true">
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-menu-button></ion-menu-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Dateien</ion-title>
|
||||
<ion-progress-bar type="indeterminate" *ngIf="loading" />
|
||||
<ion-progress-bar [value]="progress" *ngIf="progress != -1" />
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content [fullscreen]="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Dateien</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<ion-button (click)="upload.click()"><ion-icon ios="arrow-up-circle-outline" md="arrow-up-circle-sharp" /></ion-button>
|
||||
<ion-button id="create-folder"><ion-icon ios="add-circle-outline" md="add-circle-sharp" ></ion-icon></ion-button>
|
||||
<form #uploadForm>
|
||||
<input type="file" hidden="hidden" multiple (change)="onUpload(upload.files, uploadForm)" #upload>
|
||||
</form>
|
||||
|
||||
<ion-modal trigger="create-folder" (willDismiss)="createFolder($event)" #modal>
|
||||
<ng-template>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-button (click)="modal.dismiss(null, 'cancel')">Abbrechen</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Neuer Ordner</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button (click)="modal.dismiss(newFolder.value, 'confirm')" [strong]="true">Erstellen</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding">
|
||||
<ion-item>
|
||||
<ion-label position="stacked">Name</ion-label>
|
||||
<ion-input aria-label="Name" type="text" #newFolder/>
|
||||
</ion-item>
|
||||
</ion-content>
|
||||
</ng-template>
|
||||
</ion-modal>
|
||||
</ion-col>
|
||||
<ion-col *ngIf="clipboard">
|
||||
<ion-button (click)="onMove()">Verschieben</ion-button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
|
||||
<section class="container">
|
||||
<ion-list>
|
||||
<ion-list-header>{{currentDirectory}}</ion-list-header>
|
||||
|
||||
<ion-item *ngIf="currentDirectory != '/'">
|
||||
<ion-icon ios="folder-outline" md="folder-sharp"></ion-icon>
|
||||
<ion-label (click)="goUpFolder()">Übergeordnetes Verzeichnis</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item *ngFor="let item of directoryContent">
|
||||
<ion-icon [ios]="(item.type == 'dir' ? 'folder' : 'document') + '-outline'" [md]="(item.type == 'dir' ? 'folder' : 'document') + '-sharp'" />
|
||||
<ion-label (click)="interact(item)">{{item.name}}</ion-label>
|
||||
<ion-button fill="none" (click)="openMenu(item)">
|
||||
<ion-icon ios="ellipsis-vertical-outline" md="ellipsis-vertical-sharp" />
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</section>
|
||||
</ion-content>
|
||||
|
||||
<ion-footer>
|
||||
<ion-toolbar>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<ion-tab-button (click)="switchDirectory('/Files')" [ngClass]="{'active': currentDirectory.startsWith('/Files')}">
|
||||
<ion-icon ios="folder-outline" md="folder-sharp" />
|
||||
Eigene
|
||||
</ion-tab-button>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<ion-tab-button (click)="switchDirectory('/Groups')" [ngClass]="{'active': currentDirectory.startsWith('/Groups')}">
|
||||
<ion-icon ios="people-outline" md="people-sharp" />
|
||||
Gruppen
|
||||
</ion-tab-button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
8
BetterIServ.Mobile/src/app/pages/files/files.page.scss
Normal file
8
BetterIServ.Mobile/src/app/pages/files/files.page.scss
Normal file
@@ -0,0 +1,8 @@
|
||||
ion-label {
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: var(--ion-color-primary);
|
||||
}
|
||||
173
BetterIServ.Mobile/src/app/pages/files/files.page.ts
Normal file
173
BetterIServ.Mobile/src/app/pages/files/files.page.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {ActionSheetController, AlertController, IonicModule, Platform} from '@ionic/angular';
|
||||
import {WebdavService} from "../../api/webdav.service";
|
||||
import {DirectoryContent} from "../../entities/directoryContent";
|
||||
import {File} from "@awesome-cordova-plugins/file/ngx";
|
||||
import {saveAs} from "file-saver";
|
||||
import {HttpDownloadProgressEvent, HttpEventType} from "@angular/common/http";
|
||||
|
||||
@Component({
|
||||
selector: 'app-files',
|
||||
templateUrl: './files.page.html',
|
||||
styleUrls: ['./files.page.scss'],
|
||||
standalone: true,
|
||||
imports: [IonicModule, CommonModule, FormsModule]
|
||||
})
|
||||
export class FilesPage implements OnInit {
|
||||
|
||||
public currentDirectory: string = "/Files/";
|
||||
public directoryContent: DirectoryContent[];
|
||||
public clipboard: DirectoryContent = undefined;
|
||||
public loading: boolean = true;
|
||||
|
||||
public progress: number = -1;
|
||||
|
||||
constructor(private webdav: WebdavService, private platform: Platform, private menus: ActionSheetController, private alerts: AlertController) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.directoryContent = await this.webdav.getDirectory(this.currentDirectory);
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
public async switchDirectory(dir: string) {
|
||||
this.loading = true;
|
||||
this.directoryContent = await this.webdav.getDirectory(dir);
|
||||
this.currentDirectory = dir;
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
public async goUpFolder() {
|
||||
const split = this.currentDirectory.split("/");
|
||||
await this.switchDirectory(this.currentDirectory.replace(split[split.length - 2] + "/", ""));
|
||||
}
|
||||
|
||||
public async interact(item: DirectoryContent) {
|
||||
if (item.type == "dir") {
|
||||
await this.switchDirectory(item.url);
|
||||
}else {
|
||||
this.webdav.downloadFile(item.url).subscribe(async event => {
|
||||
if (event.type == HttpEventType.DownloadProgress) {
|
||||
const e = event as HttpDownloadProgressEvent;
|
||||
this.progress = e.loaded / e.total * 100;
|
||||
}
|
||||
|
||||
if (event.type == HttpEventType.Response) {
|
||||
const blob = event.body;
|
||||
const file = new File();
|
||||
|
||||
if (this.platform.is('desktop')) {
|
||||
saveAs(blob, item.name);
|
||||
this.progress = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
const downloadPath = (
|
||||
this.platform.is('android')
|
||||
) ? file.externalDataDirectory : file.documentsDirectory;
|
||||
await file.writeFile(downloadPath, item.name, blob, {replace: true});
|
||||
this.progress = -1;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public async openMenu(item: DirectoryContent) {
|
||||
const menu = await this.menus.create({
|
||||
header: item.name,
|
||||
buttons: [
|
||||
{
|
||||
text: "Löschen",
|
||||
role: "destructive",
|
||||
data: {action: "delete"}
|
||||
},
|
||||
{
|
||||
text: "Verschieben",
|
||||
data: {action: "move"}
|
||||
},
|
||||
{
|
||||
text: "Abbrechen",
|
||||
role: "cancel",
|
||||
data: {action: "cancel"}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
await menu.present();
|
||||
const result = await menu.onDidDismiss<{action: string}>();
|
||||
|
||||
if (result.data?.action == undefined) return;
|
||||
if (result.data.action == "delete") {
|
||||
const alert = await this.alerts.create({
|
||||
subHeader: "Möchtest du dieses Element wirklich löschen?",
|
||||
message: item.name,
|
||||
buttons: [
|
||||
{
|
||||
text: "Abbrechen",
|
||||
role: "cancel"
|
||||
},
|
||||
{
|
||||
text: "Löschen",
|
||||
role: "destructive"
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
await alert.present();
|
||||
const result = await alert.onDidDismiss();
|
||||
if (result.role == "destructive") {
|
||||
this.loading = true;
|
||||
await this.webdav.delete(item.url);
|
||||
await this.switchDirectory(this.currentDirectory);
|
||||
this.loading = false;
|
||||
|
||||
await (await this.alerts.create({
|
||||
header: "Element gelöscht!",
|
||||
buttons: ["Ok"]
|
||||
})).present();
|
||||
}
|
||||
}
|
||||
if (result.data.action == "move") {
|
||||
this.clipboard = item;
|
||||
}
|
||||
}
|
||||
|
||||
public async onUpload(files: FileList, form: HTMLFormElement) {
|
||||
this.loading = true;
|
||||
const uploads: Promise<void>[] = [];
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files.item(i);
|
||||
uploads.push(new Promise<void>(resolve => {
|
||||
this.webdav.uploadFile(this.currentDirectory + file.name, file).subscribe(event => {
|
||||
if (event.type == HttpEventType.Response) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}))
|
||||
}
|
||||
|
||||
await Promise.all(uploads);
|
||||
await this.switchDirectory(this.currentDirectory);
|
||||
this.loading = false;
|
||||
form.reset();
|
||||
}
|
||||
|
||||
public async createFolder(event: any) {
|
||||
if (event.detail.data == null) return;
|
||||
this.loading = true;
|
||||
await this.webdav.createFolder(this.currentDirectory + event.detail.data);
|
||||
await this.switchDirectory(this.currentDirectory);
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
public async onMove() {
|
||||
this.loading = true;
|
||||
await this.webdav.moveElement(this.clipboard.url, this.currentDirectory + this.clipboard.name);
|
||||
await this.switchDirectory(this.currentDirectory);
|
||||
this.loading = false;
|
||||
delete this.clipboard;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,9 +13,4 @@
|
||||
<ion-title size="large">Übersicht</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<div id="container">
|
||||
<strong class="capitalize">Übersicht</strong>
|
||||
<p>Explore <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p>
|
||||
</div>
|
||||
</ion-content>
|
||||
1
BetterIServ.Mobile/src/app/pages/home/home.page.scss
Normal file
1
BetterIServ.Mobile/src/app/pages/home/home.page.scss
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import {AlertController, IonicModule} from '@ionic/angular';
|
||||
import {IServService} from "../Api/iserv.service";
|
||||
import {IServService} from "../../api/iserv.service";
|
||||
import {Router} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
@@ -24,3 +24,7 @@
|
||||
@import "@ionic/angular/css/text-alignment.css";
|
||||
@import "@ionic/angular/css/text-transformation.css";
|
||||
@import "@ionic/angular/css/flex-utils.css";
|
||||
|
||||
ion-menu-button {
|
||||
color: var(--ion-color-primary);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"strict": false,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
|
||||
Reference in New Issue
Block a user