mirror of https://github.com/Squidex/squidex.git
40 changed files with 378 additions and 359 deletions
@ -0,0 +1,31 @@ |
|||||
|
// ==========================================================================
|
||||
|
// FileExtensions.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.IO; |
||||
|
|
||||
|
// ReSharper disable InvertIf
|
||||
|
|
||||
|
namespace Squidex.Infrastructure |
||||
|
{ |
||||
|
public static class FileExtensions |
||||
|
{ |
||||
|
public static string FileType(this string fileName) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var fileInfo = new FileInfo(fileName); |
||||
|
|
||||
|
return fileInfo.Extension.Substring(1).ToLowerInvariant(); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
return "blob"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import { FileSizePipe, KNumberPipe } from './..'; |
||||
|
|
||||
|
describe('FileSizePipe', () => { |
||||
|
it('should calculate correct human file size', () => { |
||||
|
const pipe = new FileSizePipe(); |
||||
|
|
||||
|
expect(pipe.transform(50)).toBe('50 B'); |
||||
|
expect(pipe.transform(1024)).toBe('1.0 kB'); |
||||
|
expect(pipe.transform(1260000)).toBe('1.2 MB'); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('KNumberPipe', () => { |
||||
|
it('should calculate correct human string', () => { |
||||
|
const pipe = new KNumberPipe(); |
||||
|
|
||||
|
expect(pipe.transform(0)).toBe('0'); |
||||
|
expect(pipe.transform(-1)).toBe(''); |
||||
|
expect(pipe.transform(50)).toBe('50'); |
||||
|
expect(pipe.transform(1024)).toBe('1k'); |
||||
|
expect(pipe.transform(1260000)).toBe('1000k'); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,50 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import { Pipe, PipeTransform } from '@angular/core'; |
||||
|
|
||||
|
@Pipe({ |
||||
|
name: 'sqxKNumber', |
||||
|
pure: true |
||||
|
}) |
||||
|
export class KNumberPipe implements PipeTransform { |
||||
|
public transform(value: number) { |
||||
|
if (value > 1000) { |
||||
|
value = value / 1000; |
||||
|
|
||||
|
if (value < 10) { |
||||
|
value = Math.round(value * 10) / 10; |
||||
|
} else { |
||||
|
value = Math.round(value); |
||||
|
} |
||||
|
|
||||
|
return value + 'k'; |
||||
|
} else if (value < 0) { |
||||
|
return ''; |
||||
|
} else { |
||||
|
return value.toString(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Pipe({ |
||||
|
name: 'sqxFileSize', |
||||
|
pure: true |
||||
|
}) |
||||
|
export class FileSizePipe implements PipeTransform { |
||||
|
public transform(value: number) { |
||||
|
let u = 0, s = 1024; |
||||
|
|
||||
|
while (value >= s || -value >= s) { |
||||
|
value /= s; |
||||
|
u++; |
||||
|
} |
||||
|
|
||||
|
return (u ? value.toFixed(1) + ' ' : value) + ' kMGTPEZY'[u] + 'B'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -1,75 +0,0 @@ |
|||||
/* |
|
||||
* Squidex Headless CMS |
|
||||
* |
|
||||
* @license |
|
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
|
||||
*/ |
|
||||
|
|
||||
import { ApiUrlConfig, DateTime, Version } from 'framework'; |
|
||||
|
|
||||
import { FileHelper } from './file-helper'; |
|
||||
import { AssetDto } from './../services/assets.service'; |
|
||||
|
|
||||
describe('FileHelper', () => { |
|
||||
const now = DateTime.now(); |
|
||||
const user = 'user'; |
|
||||
|
|
||||
it('should calculate correct human file size', () => { |
|
||||
expect(FileHelper.fileSize(50)).toBe('50 B'); |
|
||||
expect(FileHelper.fileSize(1024)).toBe('1.0 kB'); |
|
||||
expect(FileHelper.fileSize(1260000)).toBe('1.2 MB'); |
|
||||
}); |
|
||||
|
|
||||
it('should calculate icon', () => { |
|
||||
expect(FileHelper.fileIcon('video/mp4')).toBe('/images/asset_video.png'); |
|
||||
expect(FileHelper.fileIcon('application/text')).toBe('/images/asset_generic.png'); |
|
||||
expect(FileHelper.fileIcon('application/msword')).toBe('/images/asset_doc.png'); |
|
||||
}); |
|
||||
|
|
||||
it('should calculate file type', () => { |
|
||||
expect(FileHelper.fileType('video/mp4', 'test.mp4')).toBe('mp4'); |
|
||||
expect(FileHelper.fileType('video/mp4')).toBe('mp4'); |
|
||||
expect(FileHelper.fileType('application/text', 'test.txt')).toBe('txt'); |
|
||||
expect(FileHelper.fileType('application/text')).toBe('text'); |
|
||||
|
|
||||
expect(FileHelper.fileType('invalid')).toBeUndefined(); |
|
||||
expect(FileHelper.fileType(null!)).toBeUndefined(); |
|
||||
}); |
|
||||
|
|
||||
it('should calculate asset info for image asset', () => { |
|
||||
const asset = new AssetDto('1', user, user, now, now, 'File.png', 50, 1, 'image/png', true, 100, 20, new Version('123')); |
|
||||
|
|
||||
expect(FileHelper.assetInfo(asset)).toBe('100x20px, 50 B'); |
|
||||
}); |
|
||||
|
|
||||
it('should calculate asset info for text asset', () => { |
|
||||
const asset = new AssetDto('1', user, user, now, now, 'File.txt', 50, 1, 'text/plain', false, 0, 0, null!); |
|
||||
|
|
||||
expect(FileHelper.assetInfo(asset)).toBe('50 B'); |
|
||||
}); |
|
||||
|
|
||||
it('should return asset name', () => { |
|
||||
const asset = new AssetDto('1', user, user, now, now, 'File.txt', 50, 1, 'text/plain', false, 0, 0, null!); |
|
||||
|
|
||||
expect(FileHelper.assetName(asset)).toBe('File.txt'); |
|
||||
}); |
|
||||
|
|
||||
it('should return empty string for invalid asset', () => { |
|
||||
expect(FileHelper.assetInfo(undefined!)).toBe(''); |
|
||||
expect(FileHelper.assetInfo(null!)).toBe(''); |
|
||||
}); |
|
||||
|
|
||||
it('should return preview url', () => { |
|
||||
const apiUrl = new ApiUrlConfig('my/'); |
|
||||
const asset = new AssetDto('1', user, user, now, now, 'File.txt', 50, 1, 'text/plain', false, 0, 0, new Version('123')); |
|
||||
|
|
||||
expect(FileHelper.assetPreviewUrl(apiUrl, asset)).toBe('my/api/assets/1?version=123'); |
|
||||
}); |
|
||||
|
|
||||
it('should return download url', () => { |
|
||||
const apiUrl = new ApiUrlConfig('my/'); |
|
||||
const asset = new AssetDto('1', user, user, now, now, 'File.txt', 50, 1, 'text/plain', false, 0, 0, new Version('123')); |
|
||||
|
|
||||
expect(FileHelper.assetUrl(apiUrl, asset).startsWith('my/api/assets/1?q=')).toBeTruthy(); |
|
||||
}); |
|
||||
}); |
|
||||
@ -1,112 +0,0 @@ |
|||||
/* |
|
||||
* Squidex Headless CMS |
|
||||
* |
|
||||
* @license |
|
||||
* Copyright (c) Sebastian Stehle. All rights reserved |
|
||||
*/ |
|
||||
|
|
||||
import { ApiUrlConfig, MathHelper } from 'framework'; |
|
||||
import { AssetDto } from './../services/assets.service'; |
|
||||
|
|
||||
const mimeMapping = { |
|
||||
'pdf': 'pdf', |
|
||||
'vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx', |
|
||||
'vnd.openxmlformats-officedocument.wordprocessingml.template': 'docx', |
|
||||
'vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx', |
|
||||
'vnd.openxmlformats-officedocument.spreadsheetml.template': 'xlsx', |
|
||||
'vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx', |
|
||||
'vnd.openxmlformats-officedocument.presentationml.template': 'pptx', |
|
||||
'vnd.openxmlformats-officedocument.presentationml.slideshow': 'pptx', |
|
||||
'msword': 'doc', |
|
||||
'vnd.ms-word': 'doc', |
|
||||
'vnd.ms-word.document.macroEnabled.12': 'docx', |
|
||||
'vnd.ms-word.template.macroEnabled.12': 'docx', |
|
||||
'vnd.ms-excel': 'xls', |
|
||||
'vnd.ms-excel.sheet.macroEnabled.12': 'xlsx', |
|
||||
'vnd.ms-excel.template.macroEnabled.12': 'xlsx', |
|
||||
'vnd.ms-excel.addin.macroEnabled.12': 'xlsx', |
|
||||
'vnd.ms-excel.sheet.binary.macroEnabled.12': 'xlsx', |
|
||||
'vnd.ms-powerpoint': 'ppt', |
|
||||
'vnd.ms-powerpoint.addin.macroEnabled.12': 'pptx', |
|
||||
'vnd.ms-powerpoint.presentation.macroEnabled.12': 'pptx', |
|
||||
'vnd.ms-powerpoint.template.macroEnabled.12': 'pptx', |
|
||||
'vnd.ms-powerpoint.slideshow.macroEnabled.12': 'pptx' |
|
||||
}; |
|
||||
|
|
||||
export module FileHelper { |
|
||||
export function assetUrl(apiUrl: ApiUrlConfig, asset: AssetDto): string { |
|
||||
return apiUrl.buildUrl(`api/assets/${asset.id}?q=${MathHelper.guid()}`); |
|
||||
} |
|
||||
|
|
||||
export function assetName(asset: AssetDto): string { |
|
||||
return asset.fileName; |
|
||||
} |
|
||||
|
|
||||
export function assetPreviewUrl(apiUrl: ApiUrlConfig, asset: AssetDto) { |
|
||||
return apiUrl.buildUrl(`api/assets/${asset.id}?version=${asset.version.value}`); |
|
||||
} |
|
||||
|
|
||||
export function assetInfo(asset: AssetDto): string { |
|
||||
let result = ''; |
|
||||
|
|
||||
if (asset != null) { |
|
||||
if (asset.pixelWidth) { |
|
||||
result = `${asset.pixelWidth}x${asset.pixelHeight}px, `; |
|
||||
} |
|
||||
|
|
||||
result += FileHelper.fileSize(asset.fileSize); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
export function fileType(mimeType: string, fileName?: string) { |
|
||||
if (fileName) { |
|
||||
const parts = fileName.split('.'); |
|
||||
|
|
||||
if (parts.length > 1) { |
|
||||
return parts[parts.length - 1].toLowerCase(); |
|
||||
} |
|
||||
} |
|
||||
if (mimeType) { |
|
||||
const parts = mimeType.split('/'); |
|
||||
|
|
||||
if (parts.length === 2) { |
|
||||
const mimeSuffix = parts[1].toLowerCase(); |
|
||||
|
|
||||
return mimeMapping[mimeSuffix] || mimeSuffix; |
|
||||
} |
|
||||
} |
|
||||
return undefined; |
|
||||
} |
|
||||
|
|
||||
export function fileIcon(mimeType: string) { |
|
||||
const mimeParts = mimeType.split('/'); |
|
||||
|
|
||||
let mimeIcon = 'generic'; |
|
||||
|
|
||||
if (mimeParts.length === 2) { |
|
||||
const mimePrefix = mimeParts[0].toLowerCase(); |
|
||||
const mimeSuffix = mimeParts[1].toLowerCase(); |
|
||||
|
|
||||
if (mimePrefix === 'video') { |
|
||||
mimeIcon = 'video'; |
|
||||
} else { |
|
||||
mimeIcon = mimeMapping[mimeSuffix] || 'generic'; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return `/images/asset_${mimeIcon}.png`; |
|
||||
} |
|
||||
|
|
||||
export function fileSize(bytes: number) { |
|
||||
let u = 0, s = 1024; |
|
||||
|
|
||||
while (bytes >= s || -bytes >= s) { |
|
||||
bytes /= s; |
|
||||
u++; |
|
||||
} |
|
||||
|
|
||||
return (u ? bytes.toFixed(1) + ' ' : bytes) + ' kMGTPEZY'[u] + 'B'; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,38 @@ |
|||||
|
// ==========================================================================
|
||||
|
// FileExtensionsTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Infrastructure |
||||
|
{ |
||||
|
public class FileExtensionsTests |
||||
|
{ |
||||
|
[Theory] |
||||
|
[InlineData("test.mp4", "mp4")] |
||||
|
[InlineData("test.MP4", "mp4")] |
||||
|
[InlineData("test.txt", "txt")] |
||||
|
[InlineData("test.TXT", "txt")] |
||||
|
public void Should_calculate_file_type(string fileName, string expected) |
||||
|
{ |
||||
|
var actual = fileName.FileType(); |
||||
|
|
||||
|
Assert.Equal(expected, actual); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData("")] |
||||
|
[InlineData(" ")] |
||||
|
[InlineData(null)] |
||||
|
public void Should_blob_for_invalid_file_types(string fileName) |
||||
|
{ |
||||
|
var actual = fileName.FileType(); |
||||
|
|
||||
|
Assert.Equal("blob", actual); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue