Merge branch 'release/rc-v1.2.0' of https://github.com/ONLYOFFICE/DocSpace into release/rc-v1.2.0

This commit is contained in:
Timofey Boyko 2022-12-16 14:19:04 +03:00
commit d5a15412cc
37 changed files with 5353 additions and 479 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ASC.Migrations.MySql.Migrations.FilesDb
{
public partial class FilesDbContext_Upgrade1 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "has_logo",
table: "files_thirdparty_account",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "has_logo",
table: "files_folder",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "has_logo",
table: "files_thirdparty_account");
migrationBuilder.DropColumn(
name: "has_logo",
table: "files_folder");
}
}
}

View File

@ -2329,6 +2329,10 @@ namespace ASC.Migrations.MySql.Migrations
.HasColumnName("folder_type")
.HasDefaultValueSql("'0'");
b.Property<bool>("HasLogo")
.HasColumnType("tinyint(1)")
.HasColumnName("has_logo");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("varchar(512)")
@ -2502,6 +2506,10 @@ namespace ASC.Migrations.MySql.Migrations
.HasColumnName("foldersCount")
.HasDefaultValueSql("'0'");
b.Property<bool>("HasLogo")
.HasColumnType("tinyint(1)")
.HasColumnName("has_logo");
b.Property<string>("ModifiedBy")
.IsRequired()
.HasColumnType("char(38)")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ASC.Migrations.PostgreSql.Migrations.FilesDb
{
public partial class FilesDbContext_Upgrade1 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "has_logo",
schema: "onlyoffice",
table: "files_thirdparty_account",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "has_logo",
schema: "onlyoffice",
table: "files_folder",
type: "boolean",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "has_logo",
schema: "onlyoffice",
table: "files_thirdparty_account");
migrationBuilder.DropColumn(
name: "has_logo",
schema: "onlyoffice",
table: "files_folder");
}
}
}

View File

@ -2283,6 +2283,10 @@ namespace ASC.Migrations.PostgreSql.Migrations
.HasColumnType("integer")
.HasColumnName("folder_type");
b.Property<bool>("HasLogo")
.HasColumnType("boolean")
.HasColumnName("has_logo");
b.Property<string>("Password")
.IsRequired()
.HasMaxLength(100)
@ -2430,6 +2434,10 @@ namespace ASC.Migrations.PostgreSql.Migrations
.HasColumnType("integer")
.HasColumnName("foldersCount");
b.Property<bool>("HasLogo")
.HasColumnType("boolean")
.HasColumnName("has_logo");
b.Property<Guid>("ModifiedBy")
.HasMaxLength(38)
.HasColumnType("uuid")

View File

@ -32,7 +32,6 @@ const EditRoomEvent = ({
withPaging,
reloadSelection,
getRoomLogo,
}) => {
const { t } = useTranslation(["CreateEditRoomDialog", "Common", "Files"]);
@ -107,12 +106,6 @@ const EditRoomEvent = ({
});
if (!withPaging) {
const newLogo = await getRoomLogo(room.logo);
room.logoHandlers = room.logo;
room.logo = newLogo;
room.isLogoLoading = false;
setFolder(room);
}
@ -125,12 +118,6 @@ const EditRoomEvent = ({
});
} else {
if (!withPaging) {
const newLogo = await getRoomLogo(room.logo);
room.logoHandlers = room.logo;
room.logo = newLogo;
room.isLogoLoading = false;
setFolder(room);
}
// to update state info panel
@ -149,9 +136,7 @@ const EditRoomEvent = ({
};
useEffect(async () => {
const logo = item?.logo?.original
? item.logo.original
: await api.rooms.getLogoIcon(item?.logoHandlers?.original);
const logo = item?.logo?.original ? item.logo.original : "";
if (logo) {
const imgExst = logo.slice(".")[1];
@ -212,7 +197,6 @@ export default inject(
setFolder,
addLogoToRoom,
removeLogoFromRoom,
getRoomLogo,
} = filesStore;
const { createTag, fetchTags } = tagsStore;
@ -226,7 +210,6 @@ export default inject(
editRoom,
addTagsToRoom,
removeTagsFromRoom,
getRoomLogo,
createTag,
fetchTags,

View File

@ -30,10 +30,7 @@ const FilesItemTitle = ({
</StyledTitle>
);
const icon =
selection?.isRoom && selection?.logo?.medium
? selection.logo.medium
: selection.icon;
const icon = selection.icon;
return (
<StyledTitle ref={itemTitleRef}>

View File

@ -22,7 +22,6 @@ const Details = ({
isVisitor,
}) => {
const [itemProperties, setItemProperties] = useState([]);
const [largeLogoIcon, setLargeLogoIcon] = useState("");
const [isThumbnailError, setIsThumbmailError] = useState(false);
const onThumbnailError = () => setIsThumbmailError(true);
@ -39,24 +38,9 @@ const Details = ({
culture,
});
const getLargeRoomLogo = React.useCallback(
async (url) => {
if (selection?.logo?.large) return setLargeLogoIcon(selection.logo.large);
const icon = await api.rooms.getLogoIcon(url);
setLargeLogoIcon(icon);
},
[selection?.logo?.large]
);
useEffect(async () => {
setItemProperties(detailsHelper.getPropertyList());
if ((selection?.isRoom || selection?.roomType) && !selection.isArchive) {
getLargeRoomLogo(selection?.logoHandlers?.large);
}
if (
!selection.isFolder &&
selection.thumbnailStatus === 0 &&
@ -67,11 +51,13 @@ const Details = ({
) {
await createThumbnail(selection.id);
}
}, [selection, getLargeRoomLogo]);
}, [selection]);
const currentIcon = largeLogoIcon
? largeLogoIcon
: getInfoPanelItemIcon(selection, 96);
console.log(selection);
const currentIcon =
!selection.isArchive && selection?.logo?.large
? selection?.logo?.large
: getInfoPanelItemIcon(selection, 96);
return (
<>
@ -89,7 +75,10 @@ const Details = ({
<StyledNoThumbnail>
<img
className={`no-thumbnail-img ${selection.isRoom && "is-room"} ${
selection.isRoom && selection.logo?.large && "custom-logo"
selection.isRoom &&
!selection.isArchive &&
selection.logo?.large &&
"custom-logo"
}`}
src={currentIcon}
alt="thumbnail-icon-big"

View File

@ -231,7 +231,7 @@ const SimpleFilesRow = (props) => {
const element = (
<ItemIcon
id={item.id}
icon={item.isRoom && item.logo.medium ? item.logo.medium : item.icon}
icon={item.icon}
fileExst={item.fileExst}
isRoom={item.isRoom}
/>

View File

@ -324,7 +324,7 @@ const FilesTableRow = (props) => {
const element = (
<ItemIcon
id={item.id}
icon={item.isRoom && item.logo.medium ? item.logo.medium : item.icon}
icon={item.icon}
fileExst={item.fileExst}
isRoom={item.isRoom}
/>

View File

@ -68,7 +68,7 @@ const FileTile = (props) => {
const element = (
<ItemIcon
id={item.id}
icon={item.isRoom && item.logo.medium ? item.logo.medium : item.icon}
icon={item.icon}
fileExst={item.fileExst}
isRoom={item.isRoom}
/>

View File

@ -1067,8 +1067,6 @@ class FilesStore {
this.setCreatedItem(null);
}
this.updateRoomLoadingLogo();
return Promise.resolve(selectedFolder);
})
.catch((err) => {
@ -2047,48 +2045,6 @@ class FilesStore {
return folderUrl;
};
getRoomLogo = async (logoHandlers) => {
const newLogos = {};
for (let key in logoHandlers) {
let icon = "";
if (key === "medium") {
icon = await api.rooms.getLogoIcon(logoHandlers[key]);
// check for null
icon = icon ? icon : "";
}
newLogos[key] = icon;
}
return newLogos;
};
updateRoomLoadingLogo = async () => {
const newRooms = await Promise.all(
this.folders.map(async (f) => {
const newRoom = JSON.parse(JSON.stringify(f));
if (!newRoom.isLogoLoading) return newRoom;
newRoom.isLogoLoading = false;
newRoom.logo = await this.getRoomLogo(newRoom.logoHandlers);
return newRoom;
})
);
if (
(this.treeFoldersStore.isRoomsFolder ||
this.treeFoldersStore.isArchiveFolder) &&
this.selectedFolderStore.navigationPath.length === 0
) {
this.setFolders(newRooms);
}
};
get filesList() {
const { getIcon } = this.filesSettingsStore;
//return [...this.folders, ...this.files];
@ -2119,8 +2075,6 @@ class FilesStore {
foldersCount,
id,
logo,
logoHandlers,
isLogoLoading,
locked,
parentId,
pureContentLength,
@ -2170,14 +2124,6 @@ class FilesStore {
const isThirdPartyFolder = providerKey && id === rootFolderId;
const iconSize = this.viewAs === "table" ? 24 : 32;
const icon = getIcon(
iconSize,
fileExst,
providerKey,
contentLength,
roomType,
isArchive
);
let isFolder = false;
this.folders.map((x) => {
@ -2208,6 +2154,18 @@ class FilesStore {
const isRoom = !!roomType;
const icon =
isRoom && !isArchive && logo?.medium
? logo?.medium
: getIcon(
iconSize,
fileExst,
providerKey,
contentLength,
roomType,
isArchive
);
return {
access,
//checked,
@ -2226,9 +2184,8 @@ class FilesStore {
icon,
id,
isFolder,
isLogoLoading,
logo,
logoHandlers,
locked,
new: item.new,
parentId,
@ -2866,8 +2823,6 @@ class FilesStore {
this.setFolders([...this.folders, ...newFiles.folders]);
this.setFilesIsLoading(false);
});
if (isRooms) this.updateRoomLoadingLogo();
};
//Duplicate of countTilesInRow, used to update the number of tiles in a row after the window is resized.

View File

@ -24,8 +24,8 @@ class SelectedFolderStore {
roomType = null;
pinned = null;
isRoom = null;
isArchive = null;
logo = null;
logoHandlers = null;
tags = null;
rootFolderId = null;
settingsStore = null;

View File

@ -5,7 +5,7 @@ import { FolderType, RoomSearchArea } from "../../constants";
import find from "lodash/find";
import { getFolderOptions, decodeDisplayName } from "../../utils";
import { Encoder } from "../../utils/encoder";
import { getLogoIcon, getRooms } from "../rooms";
import { getRooms } from "../rooms";
import RoomsFilter from "../rooms/filter";
export function openEdit(fileId, version, doc, view) {
@ -39,45 +39,7 @@ export function getFolderInfo(folderId) {
url: `/files/folder/${folderId}`,
};
return request(options).then((res) => {
if (res.roomType) {
return new Promise((resolve, reject) => {
if (res.rootFolderType === FolderType.Archive) {
res.isLogoLoading = false;
for (let key in room.logo) {
room.logo[key] = "";
}
return resolve(res);
}
res.isLogoLoading = false;
res.logoHandlers = res.logo;
const newLogos = {};
const actions = [];
const getLogo = async (key) => {
const logo = await getLogoIcon(res.logo[key]);
newLogos[key] = logo;
};
for (let key in res.logo) {
actions.push(getLogo(key));
}
return Promise.all(actions).then(() => {
res.logo = newLogos;
resolve(res);
});
});
}
return res;
});
return request(options);
}
export function getFolderPath(folderId) {
@ -95,40 +57,9 @@ export function getFolder(folderId, filter) {
res.files = decodeDisplayName(res.files);
res.folders = decodeDisplayName(res.folders);
const { current } = res;
if (current.roomType) {
res.current.isLogoLoading = false;
res.current.logoHandlers = current.logo;
if (current.rootFolderType === FolderType.Rooms) {
return new Promise((resolve, reject) => {
const actions = [];
const newLogos = {};
const getLogo = async (key) => {
const logo = await getLogoIcon(current.logo[key]);
newLogos[key] = logo;
};
for (let key in current.logo) {
actions.push(getLogo(key));
}
return Promise.all(actions).then(() => {
res.current.logo = newLogos;
resolve(res);
});
});
} else {
for (let key in res.current.logo) {
res.current.logo[key] = "";
}
}
}
res.current.isArchive =
!!res.current.roomType &&
res.current.rootFolderType === FolderType.Archive;
return res;
});

View File

@ -15,23 +15,6 @@ export function getRooms(filter) {
if (res.current.rootFolderType === FolderType.Archive) {
res.folders.forEach((room) => {
room.isArchive = true;
room.isLogoLoading = false;
for (let key in room.logo) {
room.logo[key] = "";
}
});
} else {
res.folders.forEach((f, index) => {
res.folders[index].isLogoLoading = true;
res.folders[index].logoHandlers = f.logo;
const newLogos = {};
for (let key in f.logo) {
newLogos[key] = "";
}
res.folders[index].logo = newLogos;
});
}
@ -39,60 +22,16 @@ export function getRooms(filter) {
});
}
export function getLogoIcon(url) {
if (!url) return "";
const options = {
// baseURL: combineUrl(AppServerConfig.proxyURL, config.homepage),
method: "get",
url: `/products/files/httphandlers${url}`,
responseType: "text",
};
return request(options);
}
export function getRoomInfo(id) {
const options = {
method: "get",
url: `/files/rooms/${id}`,
};
return request(options).then(async (res) => {
return new Promise((resolve, reject) => {
if (res.rootFolderType === FolderType.Archive) {
res.isLogoLoading = false;
res.isArchive = true;
for (let key in res.logo) {
res.logo[key] = "";
}
return request(options).then((res) => {
if (res.rootFolderType === FolderType.Archive) res.isArchive = true;
return resolve(res);
}
res.isLogoLoading = false;
res.logoHandlers = res.logo;
const newLogos = {};
const actions = [];
const getLogo = async (key) => {
const logo = await getLogoIcon(res.logo[key]);
newLogos[key] = logo;
};
for (let key in res.logo) {
actions.push(getLogo(key));
}
return Promise.all(actions).then(() => {
res.logo = newLogos;
resolve(res);
});
});
return res;
});
}

View File

@ -110,7 +110,7 @@ public class FolderDtoHelper : FileEntryDtoHelper
result.Tags = folder.Tags.Select(t => t.Name);
}
result.Logo = _roomLogoManager.GetLogo(folder);
result.Logo = await _roomLogoManager.GetLogoAsync(folder);
result.RoomType = folder.FolderType switch
{
FolderType.FillingFormsRoom => RoomType.FillingFormsRoom,

View File

@ -35,6 +35,7 @@ public interface IProviderDao
IAsyncEnumerable<IProviderInfo> GetProvidersInfoAsync(Guid userId);
Task<int> SaveProviderInfoAsync(string providerKey, string customerTitle, AuthData authData, FolderType folderType);
Task<bool> UpdateProviderInfoAsync(int linkId, FolderType rootFolderType);
Task<bool> UpdateProviderInfoAsync(int linkId, bool hasLogo);
Task<bool> UpdateProviderInfoAsync(int linkId, string folderId, FolderType folderType, bool @private);
Task<int> UpdateProviderInfoAsync(int linkId, string customerTitle, AuthData authData, FolderType folderType, Guid? userId = null);
Task<int> UpdateBackupProviderInfoAsync(string providerKey, string customerTitle, AuthData authData);

View File

@ -446,6 +446,7 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
toUpdate.CreateBy = folder.CreateBy;
toUpdate.ModifiedOn = _tenantUtil.DateTimeToUtc(folder.ModifiedOn);
toUpdate.ModifiedBy = folder.ModifiedBy;
toUpdate.HasLogo = folder.HasLogo;
await filesDbContext.SaveChangesAsync();

View File

@ -42,6 +42,7 @@ public class DbFilesThirdpartyAccount : BaseEntity, IDbFile, IDbSearch
public int TenantId { get; set; }
public string FolderId { get; set; }
public bool Private { get; set; }
public bool HasLogo { get; set; }
public override object[] GetKeys()
{
@ -137,6 +138,8 @@ public static class DbFilesThirdpartyAccountExtension
.UseCollation("utf8_general_ci");
entity.Property(e => e.Private).HasColumnName("private");
entity.Property(e => e.HasLogo).HasColumnName("has_logo");
});
}
public static void PgSqlAddDbFilesThirdpartyAccount(this ModelBuilder modelBuilder)
@ -188,7 +191,9 @@ public static class DbFilesThirdpartyAccountExtension
entity.Property(e => e.FolderId).HasColumnName("folder_id");
entity.Property(e => e.Private).HasColumnName("private");
entity.Property(e => e.Private).HasColumnName("private");
entity.Property(e => e.HasLogo).HasColumnName("has_logo");
});
}
}

View File

@ -44,6 +44,7 @@ public class DbFolder : IDbFile, IDbSearch, ISearchItem
public int FoldersCount { get; set; }
public int FilesCount { get; set; }
public bool Private { get; set; }
public bool HasLogo { get; set; }
[Ignore]
public string IndexName => Tables.Folder;
@ -130,6 +131,8 @@ public static class DbFolderExtension
.UseCollation("utf8_general_ci");
entity.Property(e => e.Private).HasColumnName("private");
entity.Property(e => e.HasLogo).HasColumnName("has_logo");
});
}
public static void PgSqlAddDbFolder(this ModelBuilder modelBuilder)
@ -178,6 +181,8 @@ public static class DbFolderExtension
.HasMaxLength(400);
entity.Property(e => e.Private).HasColumnName("private");
entity.Property(e => e.HasLogo).HasColumnName("has_logo");
});
}
}

View File

@ -73,6 +73,7 @@ public class Folder<T> : FileEntry<T>, IFolder
public string FolderUrl { get; set; }
public bool Pinned { get; set; }
public bool Private { get; set; }
public bool HasLogo { get; set; }
public override bool IsNew
{
get => Convert.ToBoolean(NewForMe);

View File

@ -124,6 +124,7 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
folder.FilesCount = boxFolder.ItemCollection != null ? boxFolder.ItemCollection.Entries.Count(item => item is BoxFile) : 0;
folder.FoldersCount = boxFolder.ItemCollection != null ? boxFolder.ItemCollection.Entries.Count(item => item is BoxFolder) : 0;
folder.Private = ProviderInfo.Private;
folder.HasLogo = ProviderInfo.HasLogo;
SetFolderType(folder, isRoot);
if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc)

View File

@ -57,6 +57,7 @@ internal class BoxProviderInfo : IProviderInfo
public FolderType FolderType { get; set; }
public string FolderId { get; set; }
public bool Private { get; set; }
public bool HasLogo { get; set; }
public string BoxRootId
{

View File

@ -128,6 +128,7 @@ internal abstract class DropboxDaoBase : ThirdPartyProviderDao<DropboxProviderIn
folder.ModifiedOn = isRoot ? ProviderInfo.CreateOn : default;
folder.Title = MakeFolderTitle(dropboxFolder);
folder.Private = ProviderInfo.Private;
folder.HasLogo = ProviderInfo.HasLogo;
SetFolderType(folder, isRoot);
if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc)

View File

@ -56,6 +56,7 @@ internal class DropboxProviderInfo : IProviderInfo
public FolderType FolderType { get; set; }
public string FolderId { get; set; }
public bool Private { get; set; }
public bool HasLogo { get; set; }
private readonly DropboxStorageDisposableWrapper _wrapper;
private readonly DropboxProviderInfoHelper _dropboxProviderInfoHelper;

View File

@ -140,6 +140,7 @@ internal abstract class GoogleDriveDaoBase : ThirdPartyProviderDao<GoogleDrivePr
folder.CreateOn = isRoot ? ProviderInfo.CreateOn : (driveEntry.CreatedTime ?? default);
folder.ModifiedOn = isRoot ? ProviderInfo.CreateOn : (driveEntry.ModifiedTime ?? default);
folder.Private = ProviderInfo.Private;
folder.HasLogo = ProviderInfo.HasLogo;
SetFolderType(folder, isRoot);
folder.Title = MakeFolderTitle(driveEntry);

View File

@ -60,6 +60,7 @@ internal class GoogleDriveProviderInfo : IProviderInfo
public FolderType FolderType { get; set; }
public string FolderId { get; set; }
public bool Private { get; set; }
public bool HasLogo { get; set; }
public string DriveRootId
{
get

View File

@ -127,6 +127,7 @@ internal abstract class OneDriveDaoBase : ThirdPartyProviderDao<OneDriveProvider
folder.CreateOn = isRoot ? ProviderInfo.CreateOn : (onedriveFolder.CreatedDateTime.HasValue ? _tenantUtil.DateTimeFromUtc(onedriveFolder.CreatedDateTime.Value.DateTime) : default);
folder.ModifiedOn = isRoot ? ProviderInfo.CreateOn : (onedriveFolder.LastModifiedDateTime.HasValue ? _tenantUtil.DateTimeFromUtc(onedriveFolder.LastModifiedDateTime.Value.DateTime) : default);
folder.Private = ProviderInfo.Private;
folder.HasLogo = ProviderInfo.HasLogo;
SetFolderType(folder, isRoot);
folder.Title = MakeItemTitle(onedriveFolder);

View File

@ -57,6 +57,7 @@ internal class OneDriveProviderInfo : IProviderInfo
public FolderType FolderType { get; set; }
public string FolderId { get; set; }
public bool Private { get; set; }
public bool HasLogo { get; set; }
private readonly OneDriveStorageDisposableWrapper _wrapper;
private readonly OneDriveProviderInfoHelper _oneDriveProviderInfoHelper;

View File

@ -229,6 +229,26 @@ internal class ProviderAccountDao : IProviderDao
return true;
}
public async Task<bool> UpdateProviderInfoAsync(int linkId, bool hasLogo)
{
using var filesDbContext = _dbContextFactory.CreateDbContext();
var forUpdate = await filesDbContext.ThirdpartyAccount
.Where(r => r.Id == linkId)
.Where(r => r.TenantId == TenantID)
.FirstOrDefaultAsync();
if (forUpdate == null)
{
return false;
}
forUpdate.HasLogo = hasLogo;
await filesDbContext.SaveChangesAsync();
return true;
}
public async Task<bool> UpdateProviderInfoAsync(int linkId, string folderId, FolderType roomType, bool @private)
{
using var filesDbContext = _dbContextFactory.CreateDbContext();
@ -496,6 +516,7 @@ internal class ProviderAccountDao : IProviderDao
var folderId = input.FolderId;
var createOn = _tenantUtil.DateTimeFromUtc(input.CreateOn);
var authData = new AuthData(input.Url, input.UserName, DecryptPassword(input.Password, id), token);
var hasLogo = input.HasLogo;
if (key == ProviderTypes.Box)
{
@ -515,6 +536,7 @@ internal class ProviderAccountDao : IProviderDao
box.FolderType = folderType;
box.FolderId = folderId;
box.Private = privateRoom;
box.HasLogo = hasLogo;
return box;
}
@ -537,6 +559,7 @@ internal class ProviderAccountDao : IProviderDao
drop.FolderType = folderType;
drop.FolderId = folderId;
drop.Private = privateRoom;
drop.HasLogo = hasLogo;
return drop;
}
@ -559,6 +582,7 @@ internal class ProviderAccountDao : IProviderDao
sh.FolderType = folderType;
sh.FolderId = folderId;
sh.Private = privateRoom;
sh.HasLogo = hasLogo;
return sh;
}
@ -581,6 +605,7 @@ internal class ProviderAccountDao : IProviderDao
gd.FolderType = folderType;
gd.FolderId = folderId;
gd.Private = privateRoom;
gd.HasLogo = hasLogo;
return gd;
}
@ -603,6 +628,7 @@ internal class ProviderAccountDao : IProviderDao
od.FolderType = folderType;
od.FolderId = folderId;
od.Private = privateRoom;
od.HasLogo = hasLogo;
return od;
}
@ -633,6 +659,7 @@ internal class ProviderAccountDao : IProviderDao
sharpBoxProviderInfo.FolderType = folderType;
sharpBoxProviderInfo.FolderId = folderId;
sharpBoxProviderInfo.Private = privateRoom;
sharpBoxProviderInfo.HasLogo = hasLogo;
return sharpBoxProviderInfo;
}

View File

@ -45,6 +45,7 @@ public class SharePointProviderInfo : IProviderInfo
public string SpRootFolderId { get; set; } = "/Shared Documents";
public string FolderId { get; set; }
public bool Private { get; set; }
public bool HasLogo { get; set; }
public SharePointProviderInfo(
ILogger<SharePointProviderInfo> logger,
@ -576,6 +577,7 @@ public class SharePointProviderInfo : IProviderInfo
result.FoldersCount = 0;
result.Error = errorFolder.Error;
result.Private = Private;
result.HasLogo = HasLogo;
return result;
}
@ -599,6 +601,7 @@ public class SharePointProviderInfo : IProviderInfo
result.FilesCount = 0;
result.FoldersCount = 0;
result.Private = Private;
result.HasLogo = HasLogo;
SetFolderType(result, isRoot);

View File

@ -310,6 +310,7 @@ internal abstract class SharpBoxDaoBase : ThirdPartyProviderDao<SharpBoxProvider
folder.FilesCount = 0; /*fsEntry.Count - childFoldersCount NOTE: Removed due to performance isssues*/
folder.FoldersCount = 0; /*childFoldersCount NOTE: Removed due to performance isssues*/
folder.Private = ProviderInfo.Private;
folder.HasLogo = ProviderInfo.HasLogo;
SetFolderType(folder, isRoot);
if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc)

View File

@ -112,6 +112,7 @@ internal class SharpBoxProviderInfo : IProviderInfo
public FolderType FolderType { get; set; }
public string FolderId { get; set; }
public bool Private { get; set; }
public bool HasLogo { get; set; }
private readonly SharpBoxStorageDisposableWrapper _wrapper;
}

View File

@ -31,16 +31,14 @@ namespace ASC.Files.Core.VirtualRooms;
[Scope]
public class RoomLogoManager
{
private const string LogosPath = "{0}_size_{1}-{2}.{3}";
private const string LogosPath = "{0}_{1}.png";
private const string ModuleName = "room_logos";
private const string TempDomainPath = "logos_temp";
private const string ActionName = "logo";
private const string Default = "default";
private static Size _originalLogoSize = new Size(1280, 1280);
private static Size _largeLogoSize = new Size(96, 96);
private static Size _mediumLogoSize = new Size(32, 32);
private static Size _smallLogoSize = new Size(16, 16);
private static (SizeName, Size) _originalLogoSize = (SizeName.Original, new Size(1280, 1280));
private static (SizeName, Size) _largeLogoSize = (SizeName.Large, new Size(96, 96));
private static (SizeName, Size) _mediumLogoSize = (SizeName.Medium, new Size(32, 32));
private static (SizeName, Size) _smallLogoSize = (SizeName.Small, new Size(16, 16));
private readonly IDaoFactory _daoFactory;
private readonly FileSecurity _fileSecurity;
@ -48,13 +46,8 @@ public class RoomLogoManager
private readonly StorageFactory _storageFactory;
private readonly TenantManager _tenantManager;
private IDataStore _dataStore;
private readonly ICache _cache;
private readonly FilesMessageService _filesMessageService;
private static readonly Regex _pattern = new Regex(@"\d+-\d+", RegexOptions.Compiled);
private static readonly Regex _cachePattern = new Regex(@"\d+\/\S+\/\d+\/\d+", RegexOptions.Compiled);
private static readonly TimeSpan _cacheLifeTime = TimeSpan.FromMinutes(30);
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly FilesLinkUtility _filesLinkUtility;
public RoomLogoManager(
StorageFactory storageFactory,
@ -62,20 +55,16 @@ public class RoomLogoManager
IDaoFactory daoFactory,
FileSecurity fileSecurity,
ILogger<RoomLogoManager> logger,
AscCache cache,
FilesMessageService filesMessageService,
IHttpContextAccessor httpContextAccessor,
FilesLinkUtility filesLinkUtility)
IHttpContextAccessor httpContextAccessor)
{
_storageFactory = storageFactory;
_tenantManager = tenantManager;
_daoFactory = daoFactory;
_fileSecurity = fileSecurity;
_logger = logger;
_cache = cache;
_filesMessageService = filesMessageService;
_httpContextAccessor = httpContextAccessor;
_filesLinkUtility = filesLinkUtility;
}
public bool EnableAudit { get; set; } = true;
@ -108,8 +97,19 @@ public class RoomLogoManager
id = GetId(room);
await DeleteLogo(id);
await SaveWithProcessAsync(id, data, -1, new Point(x, y), new Size(width, height));
await RemoveTempAsync(fileName);
room.HasLogo = true;
if (room.ProviderEntry)
{
await _daoFactory.ProviderDao.UpdateProviderInfoAsync(room.ProviderId, true);
}
else
{
await folderDao.SaveFolderAsync(room);
}
if (EnableAudit)
{
@ -133,14 +133,24 @@ public class RoomLogoManager
try
{
await DeleteLogo(id);
await DataStore.DeleteFilesAsync(string.Empty, $"{ProcessFolderId(id)}*.*", false);
room.HasLogo = false;
if (room.ProviderEntry)
{
await _daoFactory.ProviderDao.UpdateProviderInfoAsync(room.ProviderId, false);
}
else
{
await folderDao.SaveFolderAsync(room);
}
if (EnableAudit)
{
_filesMessageService.Send(room, Headers, MessageAction.RoomLogoDeleted);
}
}
catch (DirectoryNotFoundException e)
catch (Exception e)
{
_logger.ErrorRemoveRoomLogo(e);
}
@ -148,24 +158,35 @@ public class RoomLogoManager
return room;
}
public Logo GetLogo<T>(Folder<T> room)
public async ValueTask<Logo> GetLogoAsync<T>(Folder<T> room)
{
var id = room.Id;
return new Logo
if (!room.HasLogo)
{
Original = GetOriginalLogoUrl(id),
Large = GetLargeLogoUrl(id),
Medium = GetMediumLogoUrl(id),
Small = GetSmallLogoUrl(id)
return new Logo
{
Original = string.Empty,
Large = string.Empty,
Medium = string.Empty,
Small = string.Empty,
};
}
var id = GetId(room);
return new Logo()
{
Original = await GetLogoPathAsync(id, SizeName.Original),
Large = await GetLogoPathAsync(id, SizeName.Large),
Medium = await GetLogoPathAsync(id, SizeName.Medium),
Small = await GetLogoPathAsync(id, SizeName.Small),
};
}
public async Task<string> SaveTempAsync(byte[] data, long maxFileSize)
{
data = UserPhotoThumbnailManager.TryParseImage(data, maxFileSize, _originalLogoSize, out var imgFormat, out _, out _);
data = UserPhotoThumbnailManager.TryParseImage(data, maxFileSize, _originalLogoSize.Item2, out _, out _, out _);
var fileName = Guid.NewGuid() + "." + CommonPhotoManager.GetImgFormatName(imgFormat);
var fileName = $"{Guid.NewGuid()}.png";
using var stream = new MemoryStream(data);
var path = await DataStore.SaveAsync(TempDomainPath, fileName, stream);
@ -177,89 +198,31 @@ public class RoomLogoManager
if (pathAsString.IndexOf('?') > 0)
{
pathWithoutQuery = pathAsString.Substring(0, pathAsString.IndexOf('?'));
}
}
return pathWithoutQuery;
}
public string GetOriginalLogoUrl<T>(T id)
public async Task RemoveTempAsync(string fileName)
{
return GetLogoUrl(id, RoomLogoSize.Original);
}
var index = fileName.LastIndexOf('.');
var fileNameWithoutExt = (index != -1) ? fileName.Substring(0, index) : fileName;
public string GetLargeLogoUrl<T>(T id)
{
return GetLogoUrl(id, RoomLogoSize.Large);
}
public string GetMediumLogoUrl<T>(T id)
{
return GetLogoUrl(id, RoomLogoSize.Medium);
}
public string GetSmallLogoUrl<T>(T id)
{
return GetLogoUrl(id, RoomLogoSize.Small);
}
public async ValueTask<string> GetMediumLogoPathAsync<T>(T id)
{
return await GetLogoPathAsync(id, _mediumLogoSize);
}
public async ValueTask<string> GetSmallLogoPathAsync<T>(T id)
{
return await GetLogoPathAsync(id, _smallLogoSize);
}
public async ValueTask<string> GetLargeLogoPathAsync<T>(T id)
{
return await GetLogoPathAsync(id, _largeLogoSize);
}
public async ValueTask<string> GetOriginalLogoPathAsync<T>(T id)
{
return await GetLogoPathAsync(id, null, true);
}
public async Task<string> GetLogoPathAsync<T>(T id, string size)
{
var room = await _daoFactory.GetFolderDao<T>().GetFolderAsync(id);
if (room == null)
try
{
throw new ItemNotFoundException("Room not found");
await DataStore.DeleteFilesAsync(TempDomainPath, "", fileNameWithoutExt + "*.*", false);
}
if (!await _fileSecurity.CanReadAsync(room))
catch(Exception e)
{
throw new SecurityException("You don't have permission to read the room");
_logger.ErrorRemoveTempPhoto(e);
}
if (!RoomLogoSizeExtensions.TryParse(size, true, out var result))
{
throw new ArgumentException("Size not valid", nameof(size));
}
id = GetId(room);
return result switch
{
RoomLogoSize.Original => await GetOriginalLogoPathAsync(id),
RoomLogoSize.Large => await GetLargeLogoPathAsync(id),
RoomLogoSize.Medium => await GetMediumLogoPathAsync(id),
RoomLogoSize.Small => await GetSmallLogoPathAsync(id),
_ => throw new NotImplementedException()
};
}
private async Task<string> SaveWithProcessAsync<T>(T id, byte[] imageData, long maxFileSize, Point position, Size cropSize)
{
imageData = UserPhotoThumbnailManager.TryParseImage(imageData, maxFileSize, _originalLogoSize, out var imageFormat, out var width, out var height);
imageData = UserPhotoThumbnailManager.TryParseImage(imageData, maxFileSize, _originalLogoSize.Item2, out var _, out var _, out var _);
var imageExtension = CommonPhotoManager.GetImgFormatName(imageFormat);
var fileName = $"{ProcessFolderId(id)}_orig_{width}-{height}.{imageExtension}";
var fileName = string.Format(LogosPath, ProcessFolderId(id), SizeName.Original.ToStringLowerFast());
if (imageData == null || imageData.Length == 0)
{
@ -276,7 +239,7 @@ public class RoomLogoManager
return path.ToString();
}
private async Task ResizeAndSaveAsync<T>(T id, byte[] data, long maxFileSize, Size size, Point position, Size cropSize)
private async Task ResizeAndSaveAsync<T>(T id, byte[] data, long maxFileSize, (SizeName, Size) size, Point position, Size cropSize)
{
if (data == null || data.Length <= 0)
{
@ -293,9 +256,9 @@ public class RoomLogoManager
using var img = Image.Load(stream, out var format);
var imgFormat = format;
if (size != img.Size())
if (size.Item2 != img.Size())
{
using var img2 = UserPhotoThumbnailManager.GetImage(img, size, new UserPhotoThumbnailSettings(position, cropSize));
using var img2 = UserPhotoThumbnailManager.GetImage(img, size.Item2, new UserPhotoThumbnailSettings(position, cropSize));
data = CommonPhotoManager.SaveToBytes(img2);
}
else
@ -304,7 +267,7 @@ public class RoomLogoManager
}
var extension = CommonPhotoManager.GetImgFormatName(imgFormat);
var fileName = string.Format(LogosPath, ProcessFolderId(id), size.Width, size.Height, extension);
var fileName = string.Format(LogosPath, ProcessFolderId(id), size.Item1.ToStringLowerFast());
using var stream2 = new MemoryStream(data);
await DataStore.SaveAsync(fileName, stream2);
@ -315,33 +278,12 @@ public class RoomLogoManager
}
}
private string GetLogoUrl<T>(T id, RoomLogoSize size)
private async ValueTask<string> GetLogoPathAsync<T>(T id, SizeName size)
{
return $"{_filesLinkUtility.FileHandlerPath}?{FilesLinkUtility.Action}={ActionName}" +
$"&{FilesLinkUtility.FolderId}={Uri.EscapeDataString(id.ToString())}" +
$"&{FilesLinkUtility.Size}={size.ToStringLowerFast()}";
}
var fileName = string.Format(LogosPath, ProcessFolderId(id), size.ToStringLowerFast());
var uri = await DataStore.GetUriAsync(fileName);
private async ValueTask<string> GetLogoPathAsync<T>(T id, Size? size, bool original = false)
{
var key = original ? GetKey(id) : GetKey(id, size.Value);
var path = _cache.Get<string>(key);
if (path == Default)
{
return string.Empty;
}
if (!string.IsNullOrEmpty(path))
{
return await ValueTask.FromResult(path);
}
await LoadPathToCacheAsync(id);
path = _cache.Get<string>(key);
return path == null || path == Default ? string.Empty : path;
return uri.ToString();
}
private async Task<byte[]> GetTempAsync(string fileName)
@ -364,37 +306,6 @@ public class RoomLogoManager
return data.ToArray();
}
private async Task LoadPathToCacheAsync<T>(T id)
{
var logoPath = await DataStore.ListFilesAsync(string.Empty, $"{ProcessFolderId(id)}*", false)
.Select(u => u.ToString()).ToListAsync();
if (logoPath.Count == 0)
{
SetDefaultCache(id);
return;
}
var original = logoPath.Where(u => u.Contains("orig")).FirstOrDefault();
_cache.Insert(GetKey(id), original, _cacheLifeTime);
logoPath.Remove(original);
foreach (var (k, v) in logoPath.ToDictionary(p => _pattern.Match(p).Value.Split('-')))
{
_cache.Insert(GetKey(id, new Size(int.Parse(k[0]), int.Parse(k[1]))), v, _cacheLifeTime);
}
}
private async Task DeleteLogo<T>(T id)
{
await DataStore.DeleteFilesAsync(string.Empty, $"{ProcessFolderId(id)}*.*", false);
_cache.Remove(_cachePattern);
_cache.Remove(GetKey(id));
}
private string ProcessFolderId<T>(T id)
{
ArgumentNullException.ThrowIfNull(id, nameof(id));
@ -404,24 +315,6 @@ public class RoomLogoManager
: id.ToString()?.Replace("-", "").Replace("|", "");
}
private string GetKey<T>(T id, Size size)
{
return $"{TenantId}/{id}/{size.Width}/{size.Height}";
}
private string GetKey<T>(T id)
{
return $"{TenantId}/{id}/orig";
}
private void SetDefaultCache<T>(T id)
{
_cache.Insert(GetKey(id), Default, _cacheLifeTime);
_cache.Insert(GetKey(id, _largeLogoSize), Default, _cacheLifeTime);
_cache.Insert(GetKey(id, _mediumLogoSize), Default, _cacheLifeTime);
_cache.Insert(GetKey(id, _smallLogoSize), Default, _cacheLifeTime);
}
private T GetId<T>(Folder<T> room)
{
return room.ProviderEntry && (room.RootId.ToString().Contains("sbox")
@ -430,7 +323,7 @@ public class RoomLogoManager
}
[EnumExtensions]
public enum RoomLogoSize
public enum SizeName
{
Original = 0,
Large = 1,

View File

@ -196,9 +196,6 @@ public class FileHandlerService
case "track":
await TrackFile(context);
break;
case "logo":
await GetRoomLogoPathAsync(context);
break;
default:
throw new HttpException((int)HttpStatusCode.BadRequest, FilesCommonResource.ErrorMassage_BadRequest);
}
@ -1569,60 +1566,6 @@ public class FileHandlerService
await context.Response.WriteAsync(TrackResponse.Serialize(result));
}
private async Task GetRoomLogoPathAsync(HttpContext context)
{
if (!_securityContext.IsAuthenticated)
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return;
}
var folderId = context.Request.Query[FilesLinkUtility.FolderId].FirstOrDefault();
var size = context.Request.Query[FilesLinkUtility.Size].FirstOrDefault();
string result;
try
{
if (int.TryParse(folderId, out var id))
{
result = await _roomLogoManager.GetLogoPathAsync(id, size);
}
else
{
result = await _roomLogoManager.GetLogoPathAsync(folderId, size);
}
}
catch(ItemNotFoundException)
{
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
return;
}
catch (SecurityException)
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return;
}
catch
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
return;
}
context.Response.Clear();
await context.Response.WriteAsync(result);
try
{
await context.Response.Body.FlushAsync();
await context.Response.CompleteAsync();
}
catch (HttpException ex)
{
_logger.Error(ex.Message);
}
}
}
public static class FileHandlerExtensions

View File

@ -30,4 +30,7 @@ public static partial class RoomLogoManagerLogger
{
[LoggerMessage(Level = LogLevel.Error, Message = "RemoveRoomLogo")]
public static partial void ErrorRemoveRoomLogo(this ILogger<RoomLogoManager> logger, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "RemoveTempPhoto")]
public static partial void ErrorRemoveTempPhoto(this ILogger<RoomLogoManager> logger, Exception exception);
}