Merge branch 'develop' into feature/rtl-interface-direction

This commit is contained in:
Aleksandr Lushkin 2023-07-28 10:10:35 +02:00
commit 45510eb3bc
33 changed files with 880 additions and 5023 deletions

View File

@ -109,6 +109,7 @@ public abstract class BaseStartup
.AddBaseDbContextPool<TelegramDbContext>()
.AddBaseDbContextPool<FirebaseDbContext>()
.AddBaseDbContextPool<CustomDbContext>()
.AddBaseDbContextPool<UrlShortenerDbContext>()
.AddBaseDbContextPool<WebstudioDbContext>()
.AddBaseDbContextPool<InstanceRegistrationContext>()
.AddBaseDbContextPool<IntegrationEventLogContext>()

View File

@ -52,6 +52,7 @@ public class BaseWorkerStartup
services.AddBaseDbContextPool<TelegramDbContext>();
services.AddBaseDbContextPool<FirebaseDbContext>();
services.AddBaseDbContextPool<CustomDbContext>();
services.AddBaseDbContextPool<UrlShortenerDbContext>();
services.AddBaseDbContextPool<WebstudioDbContext>();
services.AddBaseDbContextPool<InstanceRegistrationContext>();
services.AddBaseDbContextPool<IntegrationEventLogContext>();

View File

@ -26,9 +26,11 @@
namespace ASC.Core.Common.EF.Context;
public class UrlShortenerFakeDbContext : DbContext
public class UrlShortenerDbContext : DbContext
{
public UrlShortenerFakeDbContext(DbContextOptions<UrlShortenerFakeDbContext> dbContextOptions) : base(dbContextOptions)
public DbSet<ShortLink> ShortLinks { get; set; }
public UrlShortenerDbContext(DbContextOptions<UrlShortenerDbContext> dbContextOptions) : base(dbContextOptions)
{
}

View File

@ -26,9 +26,9 @@
namespace ASC.Core.Common.EF.Model;
public class ShortLinks
public class ShortLink
{
public int Id { get; set; }
public long Id { get; set; }
public string Short { get; set; }
public string Link { get; set; }
}
@ -46,7 +46,7 @@ public static class ShortLinksExtension
public static void MySqlAddShortLinks(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<ShortLinks>(entity =>
modelBuilder.Entity<ShortLink>(entity =>
{
entity.ToTable("short_links")
.HasCharSet("utf8")
@ -61,7 +61,7 @@ public static class ShortLinksExtension
entity.Property(e => e.Id)
.HasColumnName("id")
.ValueGeneratedOnAdd()
.HasColumnType("int(10)");
.HasColumnType("bigint(19)");
entity.Property(e => e.Short)
.HasColumnName("short")
@ -80,7 +80,7 @@ public static class ShortLinksExtension
public static void PgSqlAddShortLinks(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<ShortLinks>(entity =>
modelBuilder.Entity<ShortLink>(entity =>
{
entity.ToTable("short_links")
.HasCharSet("utf8")
@ -95,7 +95,7 @@ public static class ShortLinksExtension
entity.Property(e => e.Id)
.HasColumnName("id")
.ValueGeneratedOnAdd()
.HasColumnType("int(10)");
.HasColumnType("bigint(19)");
entity.Property(e => e.Short)
.HasColumnName("short")

File diff suppressed because one or more lines are too long

View File

@ -1,102 +0,0 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2020
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
const queryConsts = require('./sqlConsts');
const shortUrl = require('./urlShortener');
const auth = require('../middleware/auth');
const query = require('./sql');
const log = require('./log');
const co = require('co');
const linkReg = /http(s)?:\/\/.*/;
let urls = [];
function processError(err, res, code = 400) {
log.error((err && err.message) ? err.message : err);
res.sendStatus(code);
}
function redirect(req, res) {
let short = req.params[0];
if (short.length > 12)
{ res.sendStatus(400); return; }
let id = shortUrl.decode(short);
if (!id) { res.sendStatus(400); return; }
query(queryConsts.find, [id])
.then((result) => {
log.info("redirecting (" + short + ") to " + result[0].link);
res.redirect(result[0].link);
})
.catch((err) => processError(err, res));
}
function make(req, res) {
if (!auth(req)) { res.sendStatus(401); return; }
res.contentType('text');
if (!req.query.url || !linkReg.test(req.query.url)) { processError(new Error('Empty or wrong url'), res, 400); return }
let link = req.query.url;
co(function* () {
var result = yield query(queryConsts.exists, [link]);
var key;
if (result.length) {
if (result.short) {
res.write(result[0].short);
res.end();
return;
}
key = shortUrl.encode(result[0].id);
log.info("already created shortlink (" + key + ") for " + link);
} else {
if (urls.find(r => r === link)) {
processError(new Error('Link is already being made'), res, 500);
return;
}
result = yield query(queryConsts.insert, [link]);
key = shortUrl.encode(result.insertId);
log.info("creted new shortlink (" + key + ") for " + link);
yield query(queryConsts.update, [key, result.insertId]);
}
urls = urls.filter((item) => item !== link);
res.write(key);
res.end();
}).catch((err) => processError(err, res));
}
module.exports = {
redirect: redirect,
make: make
};

View File

@ -1,115 +0,0 @@
const winston = require("winston"),
WinstonCloudWatch = require('winston-cloudwatch');
require("winston-daily-rotate-file");
const path = require("path");
const config = require("../config");
const fs = require("fs");
const os = require("os");
const { randomUUID } = require('crypto');
const date = require('date-and-time');
let logpath = config.get("logPath");
if(logpath != null)
{
if(!path.isAbsolute(logpath))
{
logpath = path.join(__dirname, "..", logpath);
}
}
const fileName = logpath ? path.join(logpath, "web.shorturl.%DATE%.log") : path.join(__dirname, "..", "..", "..", "Logs", "web.shorturl.%DATE%.log");
const dirName = path.dirname(fileName);
const aws = config.get("aws").cloudWatch;
const accessKeyId = aws.accessKeyId;
const secretAccessKey = aws.secretAccessKey;
const awsRegion = aws.region;
const logGroupName = aws.logGroupName;
const logStreamName = aws.logStreamName;
if (!fs.existsSync(dirName)) {
fs.mkdirSync(dirName);
}
var options = {
file: {
filename: fileName,
datePattern: "MM-DD",
handleExceptions: true,
humanReadableUnhandledException: true,
zippedArchive: true,
maxSize: "50m",
maxFiles: "30d",
json: true,
},
console: {
level: "debug",
handleExceptions: true,
json: false,
colorize: true,
},
cloudWatch: {
name: 'aws',
level: "debug",
logStreamName: () => {
const hostname = os.hostname();
const now = new Date();
const guid = randomUUID();
const dateAsString = date.format(now, 'YYYY/MM/DDTHH.mm.ss');
return logStreamName.replace("${hostname}", hostname)
.replace("${applicationContext}", "UrlShortener")
.replace("${guid}", guid)
.replace("${date}", dateAsString);
},
logGroupName: logGroupName,
awsRegion: awsRegion,
jsonMessage: true,
awsOptions: {
credentials: {
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey
}
}
}
};
//const fileTransport = new winston.transports.DailyRotateFile(options.file);
let transports = [
new winston.transports.Console(options.console),
new winston.transports.DailyRotateFile(options.file)
];
if (aws != null && aws.accessKeyId !== '')
{
transports.push(new WinstonCloudWatch(options.cloudWatch));
}
//winston.exceptions.handle(fileTransport);
const customFormat = winston.format(info => {
const now = new Date();
info.date = date.format(now, 'YYYY-MM-DD HH:mm:ss');
info.applicationContext = "UrlShortener";
info.level = info.level.toUpperCase();
const hostname = os.hostname();
info["instance-id"] = hostname;
return info;
})();
module.exports = new winston.createLogger({
format: winston.format.combine(
customFormat,
winston.format.json()
),
transports: transports,
exitOnError: false,
});

View File

@ -1,93 +0,0 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2020
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
const sql = require('mysql2');
const log = require('./log');
const config = require('../config');
const co = require('co');
var connection;
function createNewConnection() {
return new Promise((resolve, reject) => {
log.info("establishing new connection");
connection = sql.createConnection(config.get("sql"));
connect().then(resolve).catch(reject);
connection.on('error', onError);
});
}
function connect() {
return new Promise((resolve, reject) => connection.connect(function(err) {
if (err) {
connection = null;
reject(err);
return;
}
log.info("connected to sql");
resolve();
}));
}
function reconnect() {
co(function* () {
var shouldReconnect = true;
var attempts = 0;
while(shouldReconnect) {
try {
yield new Promise((resolve, reject) => setTimeout(resolve, 1000 * 5));
attempts++;
log.warn("reconnecting to sql, attempt: " + attempts);
yield createNewConnection();
shouldReconnect = false;
} catch(err) {
log.error(err);
}
}
});
}
function onError(err) {
log.error("sql error: " + err.code);
if (err.fatal) {
reconnect();
}
}
const query = (query, params) => new Promise((resolve, reject) => {
co(function* () {
if (!connection) yield createNewConnection();
}).catch(reject);
connection.query(query, params, function(err, res) {
if (err) reject(err);
resolve(res);
});
});
module.exports = query;

View File

@ -1,32 +0,0 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2020
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
module.exports = {
exists: "SELECT short,id FROM short_links WHERE link = ?",
insert: "INSERT INTO short_links SET link = ?",
update: "UPDATE short_links SET short = ? WHERE id = ?",
find: "SELECT link FROM short_links WHERE id = ?",
};

View File

@ -1,76 +0,0 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2020
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
/*
* ShortURL (https://github.com/delight-im/ShortURL)
* Copyright (c) delight.im (https://www.delight.im/)
* Licensed under the MIT License (https://opensource.org/licenses/MIT)
*/
/**
* ShortURL: Bijective conversion between natural numbers (IDs) and short strings
*
* ShortURL.encode() takes an ID and turns it into a short string
* ShortURL.decode() takes a short string and turns it into an ID
*
* Features:
* + large alphabet (51 chars) and thus very short resulting strings
* + proof against offensive words (removed 'a', 'e', 'i', 'o' and 'u')
* + unambiguous (removed 'I', 'l', '1', 'O' and '0')
*
* Example output:
* 123456789 <=> pgK8p
*/
//'23456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ-_'
var _alphabet = "5XzpDt6wZRdsTrJkSY_cgPyxN4j-fnb9WKBF8vh3GH72QqmLVCM",
_base = _alphabet.length,
_initial = _base * _base;
module.exports = {
encode: function(num) {
num += _initial;
var str = '';
while (num > 0) {
str = _alphabet.charAt(num % _base) + str;
num = Math.floor(num / _base);
}
return str;
},
decode: function(str) {
var num = 0;
for (var i = 0; i < str.length; i++) {
let index = _alphabet.indexOf(str.charAt(i));
if (index < 0) return null;
num = num * _base + index;
}
return num - _initial;
}
};

View File

@ -1,7 +0,0 @@
{
"app":{
"port": 9999,
"appsettings": "../../../config",
"environment": "Development"
}
}

View File

@ -1,69 +0,0 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2020
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
const nconf = require("nconf");
const path = require("path");
const fs = require("fs");
nconf.argv()
.env()
.file("config", path.join(__dirname, 'config.json') );
getAndSaveAppsettings();
getAndSaveSql();
module.exports = nconf;
function getAndSaveAppsettings(){
var appsettings = nconf.get("app").appsettings;
if(!path.isAbsolute(appsettings)){
appsettings =path.join(__dirname, appsettings);
}
var env = nconf.get("app").environment;
console.log('environment: ' + env);
nconf.file("appsettingsWithEnv", path.join(appsettings, 'appsettings.' + env + '.json'));
nconf.file("appsettings", path.join(appsettings, 'appsettings.json'));
nconf.file("appsettingsServices", path.join(appsettings, 'appsettings.services.json'));
}
function getAndSaveSql(){
var sql = new Map();
var connetionString = nconf.get("ConnectionStrings").default.connectionString;
var conf = connetionString.split(';');
for(let i = 0; i < conf.length; i++){
var splited = conf[i].split('=');
if(splited.Length < 2) continue;
if(splited[0] != null){
sql[splited[0]] = splited[1];
}
}
nconf.set("sql", sql);
}

View File

@ -1,50 +0,0 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2020
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
const express = require('express');
const cookieParser = require('cookie-parser');
const short = require('./app/app');
const log = require('./app/log');
log.stream = {
write: (message) => log.info(message)
};
const sql = require('./app/sql');
const query = require('./app/sqlConsts');
const config = require('./config');
const co = require('co');
var app = express();
app.use(cookieParser());
app.get('/', short.make);
app.get('/*', short.redirect);
const port = config.get("app").port;
app.listen(port, () => log.info(`Server started on port: ${port}`));

View File

@ -1,63 +0,0 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2020
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
const
config = require('../config'),
crypto = require('crypto'),
moment = require('moment');
const skey = config.get("core").machinekey;
const trustInterval = 5 * 60 * 1000;
function check(req) {
const authHeader = req.headers["authorization"] || req.cookies["authorization"];
if(!authHeader) return false;
const splitted = authHeader.split(':');
if (splitted.length < 3) return false;
const pkey = splitted[0].substr(4);
const date = splitted[1];
const orighash = splitted[2];
const timestamp = moment.utc(date, "YYYYMMDDHHmmss");
if (moment.utc() - timestamp > trustInterval) {
return false;
}
const hasher = crypto.createHmac('sha1', skey);
const hash = hasher.update(date + "\n" + pkey);
if (hash.digest('base64') !== orighash) {
return false;
}
return true;
}
module.exports = (req) => {
return check(req);
};

View File

@ -1,23 +0,0 @@
{
"name": "urlshortener-service",
"version": "1.0.0",
"description": "A service which makes short url and handles redirections.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"@aws-sdk/client-cloudwatch-logs": "^3.199.0",
"co": "^4.6.0",
"cookie-parser": "^1.4.3",
"date-and-time": "^2.4.1",
"express": "^4.16.3",
"moment": "^2.22.2",
"mysql2": "^2.1.0",
"nconf": "^0.10.0",
"request": "^2.88.0",
"winston": "^3.8.2",
"winston-cloudwatch": "^6.1.1",
"winston-daily-rotate-file": "^4.5.5"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +1,27 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
var options = new WebApplicationOptions
@ -49,4 +49,4 @@ if (!Path.IsPathRooted(conf.Path))
}
var migrationCreator = new MigrationCreator(app.Services);
migrationCreator.RunCreateMigrations(conf);
migrationCreator.RunCreateMigrations(conf);

View File

@ -1,27 +1,27 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
var options = new WebApplicationOptions
@ -48,4 +48,4 @@ foreach (var providerInfo in providersInfo.Providers)
{
var migrationCreator = new MigrationRunner(app.Services);
migrationCreator.RunApplyMigrations(AppContext.BaseDirectory, providerInfo, providersInfo.TeamlabsiteProviders.SingleOrDefault(q => q.Provider == providerInfo.Provider), configurationInfo);
}
}

View File

@ -98,6 +98,7 @@ public class MigrationContext : DbContext
public DbSet<DbFilesLink> FilesLink { get; set; }
public DbSet<DbFilesProperties> FilesProperties { get; set; }
public DbSet<FilesConverts> FilesConverts { get; set; }
public DbSet<ShortLink> ShortLink { get; set; }
public MigrationContext(DbContextOptions<MigrationContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
@ -159,6 +160,7 @@ public class MigrationContext : DbContext
.AddDbWebhooks()
.AddWebhooksConfig()
.AddWebhooksLog()
.AddShortLinks()
.AddDbFunctions();
}
}

View File

@ -56,7 +56,8 @@ public class Startup
services.AddBaseDbContextPool<UserDbContext>();
services.AddBaseDbContextPool<TelegramDbContext>();
services.AddBaseDbContextPool<FirebaseDbContext>();
services.AddBaseDbContextPool<CustomDbContext>();
services.AddBaseDbContextPool<CustomDbContext>();
services.AddBaseDbContextPool<UrlShortenerDbContext>();
services.AddBaseDbContextPool<WebstudioDbContext>();
services.AddBaseDbContextPool<InstanceRegistrationContext>();
services.AddBaseDbContextPool<IntegrationEventLogContext>();

View File

@ -183,6 +183,10 @@ server {
proxy_pass http://127.0.0.1:5001;
proxy_redirect off;
}
location ~* sh/(.*) {
proxy_pass http://127.0.0.1:5000;
}
location /api/2.0 {
location ~* /(files|privacyroom) {
@ -268,11 +272,6 @@ server {
rewrite apicache/(.*) /$1 break;
proxy_pass http://127.0.0.1:5100;
}
location /sh {
rewrite sh/(.*) /$1 break;
proxy_pass http://127.0.0.1:9999;
}
location /healthchecks {
rewrite /healthchecks/(.*)$ /$1 break;

View File

@ -4579,6 +4579,37 @@ namespace ASC.Migrations.MySql.SaaS.Migrations
b.HasAnnotation("MySql:CharSet", "utf8");
});
modelBuilder.Entity("ASC.Core.Common.EF.Model.ShortLink", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint(19)")
.HasColumnName("id");
b.Property<string>("Link")
.HasColumnType("text")
.HasColumnName("link")
.UseCollation("utf8_bin");
b.Property<string>("Short")
.HasColumnType("varchar(12)")
.HasColumnName("short")
.UseCollation("utf8_general_ci")
.HasAnnotation("MySql:CharSet", "utf8");
b.HasKey("Id")
.HasName("PRIMARY");
b.HasIndex("Short")
.IsUnique();
b.ToTable("short_links", (string)null);
b
.HasAnnotation("MySql:CharSet", "utf8")
.HasAnnotation("Relational:Collation", "utf8_general_ci");
});
modelBuilder.Entity("ASC.Core.Common.EF.Model.TelegramUser", b =>
{
b.Property<int>("TenantId")

View File

@ -1,4 +1,29 @@
using System;
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
@ -1454,6 +1479,24 @@ namespace ASC.Migrations.MySql.SaaS.Migrations
})
.Annotation("MySql:CharSet", "utf8");
migrationBuilder.CreateTable(
name: "short_links",
columns: table => new
{
id = table.Column<long>(type: "bigint(19)", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
@short = table.Column<string>(name: "short", type: "varchar(12)", nullable: true, collation: "utf8_general_ci")
.Annotation("MySql:CharSet", "utf8"),
link = table.Column<string>(type: "text", nullable: true, collation: "utf8_bin")
.Annotation("MySql:CharSet", "utf8")
},
constraints: table =>
{
table.PrimaryKey("PRIMARY", x => x.id);
})
.Annotation("MySql:CharSet", "utf8")
.Annotation("Relational:Collation", "utf8_general_ci");
migrationBuilder.InsertData(
table: "files_converts",
columns: new[] { "input", "output" },
@ -2498,6 +2541,12 @@ namespace ASC.Migrations.MySql.SaaS.Migrations
name: "visitdate",
table: "webstudio_uservisit",
column: "visitdate");
migrationBuilder.CreateIndex(
name: "IX_short_links_short",
table: "short_links",
column: "short",
unique: true);
}
/// <inheritdoc />
@ -2667,6 +2716,9 @@ namespace ASC.Migrations.MySql.SaaS.Migrations
migrationBuilder.DropTable(
name: "tenants_tenants");
migrationBuilder.DropTable(
name: "short_links");
}
}
}

View File

@ -4576,6 +4576,37 @@ namespace ASC.Migrations.MySql.SaaS.Migrations
b.HasAnnotation("MySql:CharSet", "utf8");
});
modelBuilder.Entity("ASC.Core.Common.EF.Model.ShortLink", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint(19)")
.HasColumnName("id");
b.Property<string>("Link")
.HasColumnType("text")
.HasColumnName("link")
.UseCollation("utf8_bin");
b.Property<string>("Short")
.HasColumnType("varchar(12)")
.HasColumnName("short")
.UseCollation("utf8_general_ci")
.HasAnnotation("MySql:CharSet", "utf8");
b.HasKey("Id")
.HasName("PRIMARY");
b.HasIndex("Short")
.IsUnique();
b.ToTable("short_links", (string)null);
b
.HasAnnotation("MySql:CharSet", "utf8")
.HasAnnotation("Relational:Collation", "utf8_general_ci");
});
modelBuilder.Entity("ASC.Core.Common.EF.Model.TelegramUser", b =>
{
b.Property<int>("TenantId")
@ -5845,7 +5876,7 @@ namespace ASC.Migrations.MySql.SaaS.Migrations
.UseCollation("utf8_general_ci")
.HasAnnotation("MySql:CharSet", "utf8");
b.Property<string>("FileShareOptions")
b.Property<string>("Options")
.HasColumnType("text")
.HasColumnName("options")
.UseCollation("utf8_general_ci")

View File

@ -4510,6 +4510,38 @@ namespace ASC.Migrations.PostgreSql.SaaS.Migrations
b.ToTable("Regions");
});
modelBuilder.Entity("ASC.Core.Common.EF.Model.ShortLink", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint(19)")
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Link")
.HasColumnType("text")
.HasColumnName("link")
.UseCollation("utf8_bin");
b.Property<string>("Short")
.HasColumnType("varchar(12)")
.HasColumnName("short")
.UseCollation("utf8_general_ci")
.HasAnnotation("MySql:CharSet", "utf8");
b.HasKey("Id")
.HasName("PRIMARY");
b.HasIndex("Short")
.IsUnique();
b.ToTable("short_links", (string)null);
b
.HasAnnotation("MySql:CharSet", "utf8")
.HasAnnotation("Relational:Collation", "utf8_general_ci");
});
modelBuilder.Entity("ASC.Core.Common.EF.Model.TelegramUser", b =>
{
b.Property<int>("TenantId")
@ -5718,7 +5750,7 @@ namespace ASC.Migrations.PostgreSql.SaaS.Migrations
.HasColumnName("subject")
.IsFixedLength();
b.Property<string>("FileShareOptions")
b.Property<string>("Options")
.HasColumnType("text")
.HasColumnName("options");

View File

@ -20,8 +20,6 @@ const PublicRoomBlock = (props) => {
setEditLinkPanelIsVisible,
} = props;
const [barIsVisible, setBarVisible] = useState(!isArchiveFolder);
const onAddNewLink = () => {
setLinkParams({ isEdit: false });
setEditLinkPanelIsVisible(true);
@ -29,7 +27,7 @@ const PublicRoomBlock = (props) => {
return (
<>
{barIsVisible && (
{externalLinks.length > 0 && !isArchiveFolder && (
<PublicRoomBar
headerText={t("Files:PublicRoom")}
bodyText={t("CreateEditRoomDialog:PublicRoomBarDescription")}

View File

@ -24,8 +24,6 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using UrlShortener = ASC.Web.Core.Utility.UrlShortener;
namespace ASC.Web.Files.Services.WCFService;
[Scope]
@ -68,7 +66,7 @@ public class FileStorageService //: IFileStorageService
private readonly DocumentServiceConnector _documentServiceConnector;
private readonly FileSharing _fileSharing;
private readonly NotifyClient _notifyClient;
private readonly UrlShortener _urlShortener;
private readonly IUrlShortener _urlShortener;
private readonly IServiceProvider _serviceProvider;
private readonly FileSharingAceHelper _fileSharingAceHelper;
private readonly ConsumerFactory _consumerFactory;
@ -123,7 +121,7 @@ public class FileStorageService //: IFileStorageService
DocumentServiceConnector documentServiceConnector,
FileSharing fileSharing,
NotifyClient notifyClient,
UrlShortener urlShortener,
IUrlShortener urlShortener,
IServiceProvider serviceProvider,
FileSharingAceHelper fileSharingAceHelper,
ConsumerFactory consumerFactory,
@ -2564,7 +2562,7 @@ public class FileStorageService //: IFileStorageService
try
{
return await _urlShortener.Instance.GetShortenLinkAsync(shareLink);
return await _urlShortener.GetShortenLinkAsync(shareLink);
}
catch (Exception e)
{

View File

@ -138,6 +138,7 @@ global using ASC.Web.Core.Notify;
global using ASC.Web.Core.PublicResources;
global using ASC.Web.Core.Quota;
global using ASC.Web.Core.Users;
global using ASC.Web.Core.Utility;
global using ASC.Web.Core.Utility.Skins;
global using ASC.Web.Core.WhiteLabel;
global using ASC.Web.Files;

View File

@ -1,56 +1,56 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Api.Controllers;
[Scope]
[DefaultRoute]
[ApiController]
public class PortalController : ControllerBase
{
protected Tenant Tenant { get { return _apiContext.Tenant; } }
private readonly ApiContext _apiContext;
protected readonly UserManager _userManager;
protected readonly TenantManager _tenantManager;
protected readonly ITariffService _tariffService;
private readonly CommonLinkUtility _commonLinkUtility;
private readonly UrlShortener _urlShortener;
private readonly AuthContext _authContext;
private readonly WebItemSecurity _webItemSecurity;
protected readonly SecurityContext _securityContext;
private readonly SettingsManager _settingsManager;
private readonly IMobileAppInstallRegistrator _mobileAppInstallRegistrator;
private readonly IConfiguration _configuration;
private readonly CoreBaseSettings _coreBaseSettings;
private readonly LicenseReader _licenseReader;
private readonly SetupInfo _setupInfo;
private readonly DocumentServiceLicense _documentServiceLicense;
private readonly TenantExtra _tenantExtra;
private readonly ILogger<PortalController> _log;
namespace ASC.Web.Api.Controllers;
[Scope]
[DefaultRoute]
[ApiController]
public class PortalController : ControllerBase
{
protected Tenant Tenant { get { return _apiContext.Tenant; } }
private readonly ApiContext _apiContext;
protected readonly UserManager _userManager;
protected readonly TenantManager _tenantManager;
protected readonly ITariffService _tariffService;
private readonly CommonLinkUtility _commonLinkUtility;
private readonly IUrlShortener _urlShortener;
private readonly AuthContext _authContext;
private readonly WebItemSecurity _webItemSecurity;
protected readonly SecurityContext _securityContext;
private readonly SettingsManager _settingsManager;
private readonly IMobileAppInstallRegistrator _mobileAppInstallRegistrator;
private readonly IConfiguration _configuration;
private readonly CoreBaseSettings _coreBaseSettings;
private readonly LicenseReader _licenseReader;
private readonly SetupInfo _setupInfo;
private readonly DocumentServiceLicense _documentServiceLicense;
private readonly TenantExtra _tenantExtra;
private readonly ILogger<PortalController> _log;
private readonly IHttpClientFactory _clientFactory;
private readonly ApiSystemHelper _apiSystemHelper;
private readonly CoreSettings _coreSettings;
@ -67,25 +67,25 @@ public class PortalController : ControllerBase
private readonly QuotaHelper _quotaHelper;
private readonly IEventBus _eventBus;
public PortalController(
ILogger<PortalController> logger,
ApiContext apiContext,
UserManager userManager,
TenantManager tenantManager,
ITariffService tariffService,
CommonLinkUtility commonLinkUtility,
UrlShortener urlShortener,
AuthContext authContext,
WebItemSecurity webItemSecurity,
SecurityContext securityContext,
SettingsManager settingsManager,
IMobileAppInstallRegistrator mobileAppInstallRegistrator,
TenantExtra tenantExtra,
IConfiguration configuration,
CoreBaseSettings coreBaseSettings,
LicenseReader licenseReader,
SetupInfo setupInfo,
DocumentServiceLicense documentServiceLicense,
public PortalController(
ILogger<PortalController> logger,
ApiContext apiContext,
UserManager userManager,
TenantManager tenantManager,
ITariffService tariffService,
CommonLinkUtility commonLinkUtility,
IUrlShortener urlShortener,
AuthContext authContext,
WebItemSecurity webItemSecurity,
SecurityContext securityContext,
SettingsManager settingsManager,
IMobileAppInstallRegistrator mobileAppInstallRegistrator,
TenantExtra tenantExtra,
IConfiguration configuration,
CoreBaseSettings coreBaseSettings,
LicenseReader licenseReader,
SetupInfo setupInfo,
DocumentServiceLicense documentServiceLicense,
IHttpClientFactory clientFactory,
ApiSystemHelper apiSystemHelper,
CoreSettings coreSettings,
@ -101,25 +101,25 @@ public class PortalController : ControllerBase
IHttpContextAccessor httpContextAccessor,
QuotaHelper quotaHelper,
IEventBus eventBus)
{
_log = logger;
_apiContext = apiContext;
_userManager = userManager;
_tenantManager = tenantManager;
_tariffService = tariffService;
_commonLinkUtility = commonLinkUtility;
_urlShortener = urlShortener;
_authContext = authContext;
_webItemSecurity = webItemSecurity;
_securityContext = securityContext;
_settingsManager = settingsManager;
_mobileAppInstallRegistrator = mobileAppInstallRegistrator;
_configuration = configuration;
_coreBaseSettings = coreBaseSettings;
_licenseReader = licenseReader;
_setupInfo = setupInfo;
_documentServiceLicense = documentServiceLicense;
_tenantExtra = tenantExtra;
{
_log = logger;
_apiContext = apiContext;
_userManager = userManager;
_tenantManager = tenantManager;
_tariffService = tariffService;
_commonLinkUtility = commonLinkUtility;
_urlShortener = urlShortener;
_authContext = authContext;
_webItemSecurity = webItemSecurity;
_securityContext = securityContext;
_settingsManager = settingsManager;
_mobileAppInstallRegistrator = mobileAppInstallRegistrator;
_configuration = configuration;
_coreBaseSettings = coreBaseSettings;
_licenseReader = licenseReader;
_setupInfo = setupInfo;
_documentServiceLicense = documentServiceLicense;
_tenantExtra = tenantExtra;
_clientFactory = clientFactory;
_apiSystemHelper = apiSystemHelper;
_coreSettings = coreSettings;
@ -135,61 +135,61 @@ public class PortalController : ControllerBase
_httpContextAccessor = httpContextAccessor;
_quotaHelper = quotaHelper;
_eventBus = eventBus;
}
}
[AllowNotPayment]
[HttpGet("")]
public TenantDto Get()
{
return _mapper.Map<TenantDto>(Tenant);
}
[HttpGet("users/{userID}")]
[HttpGet("")]
public TenantDto Get()
{
return _mapper.Map<TenantDto>(Tenant);
}
[HttpGet("users/{userID}")]
public async Task<UserInfo> GetUserAsync(Guid userID)
{
{
return await _userManager.GetUsersAsync(userID);
}
[HttpGet("users/invite/{employeeType}")]
}
[HttpGet("users/invite/{employeeType}")]
public async Task<object> GeInviteLinkAsync(EmployeeType employeeType)
{
{
if (!await _permissionContext.CheckPermissionsAsync(new UserSecurityProvider(Guid.Empty, employeeType), ASC.Core.Users.Constants.Action_AddRemoveUser))
{
return string.Empty;
}
}
return await _commonLinkUtility.GetConfirmationEmailUrlAsync(string.Empty, ConfirmType.LinkInvite, (int)employeeType, _authContext.CurrentAccount.ID)
+ $"&emplType={employeeType:d}";
}
[HttpPut("getshortenlink")]
public async Task<object> GetShortenLinkAsync(ShortenLinkRequestsDto inDto)
{
try
{
return await _urlShortener.Instance.GetShortenLinkAsync(inDto.Link);
}
catch (Exception ex)
{
_log.ErrorGetShortenLink(ex);
return inDto.Link;
}
}
+ $"&emplType={employeeType:d}";
}
[HttpPut("getshortenlink")]
public async Task<object> GetShortenLinkAsync(ShortenLinkRequestsDto inDto)
{
try
{
return await _urlShortener.GetShortenLinkAsync(inDto.Link);
}
catch (Exception ex)
{
_log.ErrorGetShortenLink(ex);
return inDto.Link;
}
}
[AllowNotPayment, AllowAnonymous]
[HttpGet("tenantextra")]
[HttpGet("tenantextra")]
public async Task<TenantExtraDto> GetTenantExtra(bool refresh)
{
{
var result = new TenantExtraDto
{
{
CustomMode = _coreBaseSettings.CustomMode,
Opensource = _tenantExtra.Opensource,
Enterprise = _tenantExtra.Enterprise,
EnableTariffPage = //TenantExtra.EnableTarrifSettings - think about hide-settings for opensource
(!_coreBaseSettings.Standalone || !string.IsNullOrEmpty(_licenseReader.LicensePath))
&& string.IsNullOrEmpty(_setupInfo.AmiMetaUrl)
(!_coreBaseSettings.Standalone || !string.IsNullOrEmpty(_licenseReader.LicensePath))
&& string.IsNullOrEmpty(_setupInfo.AmiMetaUrl)
&& !_coreBaseSettings.CustomMode
};
};
@ -201,120 +201,120 @@ public class PortalController : ControllerBase
result.LicenseAccept = _settingsManager.LoadForDefaultTenant<TariffSettings>().LicenseAcceptSetting;
result.DocServerUserQuota = await _documentServiceLicense.GetLicenseQuotaAsync();
result.DocServerLicense = await _documentServiceLicense.GetLicenseAsync();
}
}
return result;
}
[HttpGet("usedspace")]
[HttpGet("usedspace")]
public async Task<double> GetUsedSpaceAsync()
{
return Math.Round(
{
return Math.Round(
(await _tenantManager.FindTenantQuotaRowsAsync(Tenant.Id))
.Where(q => !string.IsNullOrEmpty(q.Tag) && new Guid(q.Tag) != Guid.Empty)
.Sum(q => q.Counter) / 1024f / 1024f / 1024f, 2);
}
[HttpGet("userscount")]
.Where(q => !string.IsNullOrEmpty(q.Tag) && new Guid(q.Tag) != Guid.Empty)
.Sum(q => q.Counter) / 1024f / 1024f / 1024f, 2);
}
[HttpGet("userscount")]
public async Task<long> GetUsersCountAsync()
{
{
return _coreBaseSettings.Personal ? 1 : (await _userManager.GetUserNamesAsync(EmployeeStatus.Active)).Length;
}
[AllowNotPayment]
[HttpGet("tariff")]
[AllowNotPayment]
[HttpGet("tariff")]
public async Task<Tariff> GetTariffAsync(bool refresh)
{
{
return await _tariffService.GetTariffAsync(Tenant.Id, refresh: refresh);
}
}
[AllowNotPayment]
[HttpGet("quota")]
[AllowNotPayment]
[HttpGet("quota")]
public async Task<TenantQuota> GetQuotaAsync()
{
{
return await _tenantManager.GetTenantQuotaAsync(Tenant.Id);
}
[HttpGet("quota/right")]
}
[HttpGet("quota/right")]
public async Task<TenantQuota> GetRightQuotaAsync()
{
{
var usedSpace = await GetUsedSpaceAsync();
var needUsersCount = await GetUsersCountAsync();
return (await _tenantManager.GetTenantQuotasAsync()).OrderBy(r => r.Price)
.FirstOrDefault(quota =>
quota.CountUser > needUsersCount
&& quota.MaxTotalSize > usedSpace);
}
[HttpGet("path")]
public object GetFullAbsolutePath(string virtualPath)
{
return _commonLinkUtility.GetFullAbsolutePath(virtualPath);
}
[HttpGet("thumb")]
public FileResult GetThumb(string url)
{
if (!_securityContext.IsAuthenticated || _configuration["bookmarking:thumbnail-url"] == null)
{
return null;
}
url = url.Replace("&amp;", "&");
url = WebUtility.UrlEncode(url);
.FirstOrDefault(quota =>
quota.CountUser > needUsersCount
&& quota.MaxTotalSize > usedSpace);
}
[HttpGet("path")]
public object GetFullAbsolutePath(string virtualPath)
{
return _commonLinkUtility.GetFullAbsolutePath(virtualPath);
}
[HttpGet("thumb")]
public FileResult GetThumb(string url)
{
if (!_securityContext.IsAuthenticated || _configuration["bookmarking:thumbnail-url"] == null)
{
return null;
}
url = url.Replace("&amp;", "&");
url = WebUtility.UrlEncode(url);
var request = new HttpRequestMessage
{
RequestUri = new Uri(string.Format(_configuration["bookmarking:thumbnail-url"], url))
};
var httpClient = _clientFactory.CreateClient();
using var response = httpClient.Send(request);
using var stream = response.Content.ReadAsStream();
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
string type;
if (response.Headers.TryGetValues("Content-Type", out var values))
{
type = values.First();
}
else
{
type = "image/png";
}
return File(bytes, type);
}
[HttpPost("present/mark")]
};
var httpClient = _clientFactory.CreateClient();
using var response = httpClient.Send(request);
using var stream = response.Content.ReadAsStream();
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
string type;
if (response.Headers.TryGetValues("Content-Type", out var values))
{
type = values.First();
}
else
{
type = "image/png";
}
return File(bytes, type);
}
[HttpPost("present/mark")]
public async Task MarkPresentAsReadedAsync()
{
try
{
{
try
{
var settings = await _settingsManager.LoadForCurrentUserAsync<OpensourceGiftSettings>();
settings.Readed = true;
settings.Readed = true;
await _settingsManager.SaveForCurrentUserAsync(settings);
}
catch (Exception ex)
{
_log.ErrorMarkPresentAsReaded(ex);
}
}
[HttpPost("mobile/registration")]
}
catch (Exception ex)
{
_log.ErrorMarkPresentAsReaded(ex);
}
}
[HttpPost("mobile/registration")]
public async Task RegisterMobileAppInstallAsync(MobileAppRequestsDto inDto)
{
{
var currentUser = await _userManager.GetUsersAsync(_securityContext.CurrentAccount.ID);
await _mobileAppInstallRegistrator.RegisterInstallAsync(currentUser.Email, inDto.Type);
}
[HttpPost("mobile/registration")]
}
[HttpPost("mobile/registration")]
public async Task RegisterMobileAppInstallAsync(MobileAppType type)
{
{
var currentUser = await _userManager.GetUsersAsync(_securityContext.CurrentAccount.ID);
await _mobileAppInstallRegistrator.RegisterInstallAsync(currentUser.Email, type);
}
@ -576,5 +576,5 @@ public class PortalController : ControllerBase
default:
throw new SecurityException("Access Denied.");
}
}
}
}

View File

@ -24,12 +24,12 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Api.Controllers.Settings;
namespace ASC.Web.Api.Controllers.Settings;
public class SettingsController : BaseSettingsController
{
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
private Tenant Tenant { get { return ApiContext.Tenant; } }
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
private Tenant Tenant { get { return ApiContext.Tenant; } }
private readonly MessageService _messageService;
private readonly ConsumerFactory _consumerFactory;
@ -51,18 +51,17 @@ public class SettingsController : BaseSettingsController
private readonly IConfiguration _configuration;
private readonly SetupInfo _setupInfo;
private readonly StatisticManager _statisticManager;
private readonly UrlShortener _urlShortener;
private readonly PasswordHasher _passwordHasher;
private readonly ILogger _log;
private readonly TelegramHelper _telegramHelper;
private readonly DnsSettings _dnsSettings;
private readonly AdditionalWhiteLabelSettingsHelperInit _additionalWhiteLabelSettingsHelper;
private readonly CustomColorThemesSettingsHelper _customColorThemesSettingsHelper;
private readonly QuotaUsageManager _quotaUsageManager;
private readonly TenantDomainValidator _tenantDomainValidator;
private readonly TelegramHelper _telegramHelper;
private readonly DnsSettings _dnsSettings;
private readonly AdditionalWhiteLabelSettingsHelperInit _additionalWhiteLabelSettingsHelper;
private readonly CustomColorThemesSettingsHelper _customColorThemesSettingsHelper;
private readonly QuotaUsageManager _quotaUsageManager;
private readonly TenantDomainValidator _tenantDomainValidator;
private readonly QuotaSyncOperation _quotaSyncOperation;
private readonly ExternalShare _externalShare;
private readonly ExternalShare _externalShare;
public SettingsController(
ILoggerProvider option,
MessageService messageService,
@ -89,16 +88,15 @@ public class SettingsController : BaseSettingsController
ProviderManager providerManager,
FirstTimeTenantSettings firstTimeTenantSettings,
TelegramHelper telegramHelper,
UrlShortener urlShortener,
PasswordHasher passwordHasher,
IHttpContextAccessor httpContextAccessor,
DnsSettings dnsSettings,
AdditionalWhiteLabelSettingsHelperInit additionalWhiteLabelSettingsHelper,
PasswordHasher passwordHasher,
IHttpContextAccessor httpContextAccessor,
DnsSettings dnsSettings,
AdditionalWhiteLabelSettingsHelperInit additionalWhiteLabelSettingsHelper,
CustomColorThemesSettingsHelper customColorThemesSettingsHelper,
QuotaSyncOperation quotaSyncOperation,
QuotaUsageManager quotaUsageManager,
TenantDomainValidator tenantDomainValidator,
ExternalShare externalShare
QuotaUsageManager quotaUsageManager,
TenantDomainValidator tenantDomainValidator,
ExternalShare externalShare
) : base(apiContext, memoryCache, webItemManager, httpContextAccessor)
{
_log = option.CreateLogger("ASC.Api");
@ -106,7 +104,7 @@ public class SettingsController : BaseSettingsController
_timeZoneConverter = timeZoneConverter;
_customNamingPeople = customNamingPeople;
_providerManager = providerManager;
_firstTimeTenantSettings = firstTimeTenantSettings;
_firstTimeTenantSettings = firstTimeTenantSettings;
_messageService = messageService;
_userManager = userManager;
_tenantManager = tenantManager;
@ -123,45 +121,44 @@ public class SettingsController : BaseSettingsController
_setupInfo = setupInfo;
_statisticManager = statisticManager;
_passwordHasher = passwordHasher;
_urlShortener = urlShortener;
_telegramHelper = telegramHelper;
_dnsSettings = dnsSettings;
_additionalWhiteLabelSettingsHelper = additionalWhiteLabelSettingsHelper;
_telegramHelper = telegramHelper;
_dnsSettings = dnsSettings;
_additionalWhiteLabelSettingsHelper = additionalWhiteLabelSettingsHelper;
_quotaSyncOperation = quotaSyncOperation;
_customColorThemesSettingsHelper = customColorThemesSettingsHelper;
_quotaUsageManager = quotaUsageManager;
_tenantDomainValidator = tenantDomainValidator;
_externalShare = externalShare;
_customColorThemesSettingsHelper = customColorThemesSettingsHelper;
_quotaUsageManager = quotaUsageManager;
_tenantDomainValidator = tenantDomainValidator;
_externalShare = externalShare;
}
[HttpGet("")]
[HttpGet("")]
[AllowNotPayment, AllowSuspended, AllowAnonymous]
public async Task<SettingsDto> GetSettingsAsync(bool? withpassword)
{
var studioAdminMessageSettings = await _settingsManager.LoadAsync<StudioAdminMessageSettings>();
var tenantCookieSettings = _settingsManager.Load<TenantCookieSettings>();
public async Task<SettingsDto> GetSettingsAsync(bool? withpassword)
{
var studioAdminMessageSettings = await _settingsManager.LoadAsync<StudioAdminMessageSettings>();
var tenantCookieSettings = _settingsManager.Load<TenantCookieSettings>();
var settings = new SettingsDto
{
Culture = Tenant.GetCulture().ToString(),
GreetingSettings = Tenant.Name == "" ? Resource.PortalName : Tenant.Name,
Personal = _coreBaseSettings.Personal,
DocSpace = !_coreBaseSettings.DisableDocSpace,
Personal = _coreBaseSettings.Personal,
DocSpace = !_coreBaseSettings.DisableDocSpace,
Standalone = _coreBaseSettings.Standalone,
BaseDomain = _coreBaseSettings.Basedomain,
Version = _configuration["version:number"] ?? "",
TenantStatus = (await _tenantManager.GetCurrentTenantAsync()).Status,
TenantAlias = Tenant.Alias,
EnableAdmMess = studioAdminMessageSettings.Enable || await _tenantExtra.IsNotPaidAsync(),
LegalTerms = _setupInfo.LegalTerms,
CookieSettingsEnabled = tenantCookieSettings.Enabled
BaseDomain = _coreBaseSettings.Basedomain,
Version = _configuration["version:number"] ?? "",
TenantStatus = (await _tenantManager.GetCurrentTenantAsync()).Status,
TenantAlias = Tenant.Alias,
EnableAdmMess = studioAdminMessageSettings.Enable || await _tenantExtra.IsNotPaidAsync(),
LegalTerms = _setupInfo.LegalTerms,
CookieSettingsEnabled = tenantCookieSettings.Enabled
};
if (!_authContext.IsAuthenticated && await _externalShare.GetLinkIdAsync() != default)
{
settings.SocketUrl = _configuration["web:hub:url"] ?? "";
}
if (!_authContext.IsAuthenticated && await _externalShare.GetLinkIdAsync() != default)
{
settings.SocketUrl = _configuration["web:hub:url"] ?? "";
}
if (_authContext.IsAuthenticated)
{
settings.TrustedDomains = Tenant.TrustedDomains;
@ -172,11 +169,11 @@ public class SettingsController : BaseSettingsController
settings.UtcHoursOffset = settings.UtcOffset.TotalHours;
settings.OwnerId = Tenant.OwnerId;
settings.NameSchemaId = _customNamingPeople.Current.Id;
settings.DomainValidator = _tenantDomainValidator;
settings.ZendeskKey = _setupInfo.ZendeskKey;
settings.BookTrainingEmail = _setupInfo.BookTrainingEmail;
settings.DocumentationEmail = _setupInfo.DocumentationEmail;
settings.SocketUrl = _configuration["web:hub:url"] ?? "";
settings.DomainValidator = _tenantDomainValidator;
settings.ZendeskKey = _setupInfo.ZendeskKey;
settings.BookTrainingEmail = _setupInfo.BookTrainingEmail;
settings.DocumentationEmail = _setupInfo.DocumentationEmail;
settings.SocketUrl = _configuration["web:hub:url"] ?? "";
settings.Firebase = new FirebaseDto
{
@ -186,32 +183,32 @@ public class SettingsController : BaseSettingsController
StorageBucket = _configuration["firebase:storageBucket"] ?? "",
MessagingSenderId = _configuration["firebase:messagingSenderId"] ?? "",
AppId = _configuration["firebase:appId"] ?? "",
MeasurementId = _configuration["firebase:measurementId"] ?? "",
DatabaseURL = _configuration["firebase:databaseURL"] ?? ""
};
settings.HelpLink = await _commonLinkUtility.GetHelpLinkAsync(_settingsManager, _additionalWhiteLabelSettingsHelper, true);
settings.ApiDocsLink = _configuration["web:api-docs"];
MeasurementId = _configuration["firebase:measurementId"] ?? "",
DatabaseURL = _configuration["firebase:databaseURL"] ?? ""
};
settings.HelpLink = await _commonLinkUtility.GetHelpLinkAsync(_settingsManager, _additionalWhiteLabelSettingsHelper, true);
settings.ApiDocsLink = _configuration["web:api-docs"];
bool debugInfo;
if (bool.TryParse(_configuration["debug-info:enabled"], out debugInfo))
{
settings.DebugInfo = debugInfo;
}
settings.Plugins = new PluginsDto();
bool pluginsEnabled;
if (bool.TryParse(_configuration["plugins:enabled"], out pluginsEnabled))
{
settings.Plugins.Enabled = pluginsEnabled;
}
settings.Plugins.Allow = _configuration.GetSection("plugins:allow").Get<List<string>>() ?? new List<string>();
}
settings.Plugins = new PluginsDto();
bool pluginsEnabled;
if (bool.TryParse(_configuration["plugins:enabled"], out pluginsEnabled))
{
settings.Plugins.Enabled = pluginsEnabled;
}
settings.Plugins.Allow = _configuration.GetSection("plugins:allow").Get<List<string>>() ?? new List<string>();
}
else
{
if (!(await _settingsManager.LoadAsync<WizardSettings>()).Completed)
if (!(await _settingsManager.LoadAsync<WizardSettings>()).Completed)
{
settings.WizardToken = _commonLinkUtility.GetToken(Tenant.Id, "", ConfirmType.Wizard, userId: Tenant.OwnerId);
}
@ -241,13 +238,13 @@ public class SettingsController : BaseSettingsController
}
[HttpPost("maildomainsettings")]
public async Task<object> SaveMailDomainSettingsAsync(MailDomainSettingsRequestsDto inDto)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
public async Task<object> SaveMailDomainSettingsAsync(MailDomainSettingsRequestsDto inDto)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
if (inDto.Type == TenantTrustedDomainsType.Custom)
{
Tenant.TrustedDomainsRaw = "";
Tenant.TrustedDomainsRaw = "";
Tenant.TrustedDomains.Clear();
foreach (var d in inDto.Domains.Select(domain => (domain ?? "").Trim().ToLower()))
{
@ -267,11 +264,11 @@ public class SettingsController : BaseSettingsController
Tenant.TrustedDomainsType = inDto.Type;
await _settingsManager.SaveAsync(new StudioTrustedDomainSettings { InviteAsUsers = inDto.InviteAsUsers });
await _settingsManager.SaveAsync(new StudioTrustedDomainSettings { InviteAsUsers = inDto.InviteAsUsers });
await _tenantManager.SaveTenantAsync(Tenant);
await _tenantManager.SaveTenantAsync(Tenant);
await _messageService.SendAsync(MessageAction.TrustedMailDomainSettingsUpdated);
await _messageService.SendAsync(MessageAction.TrustedMailDomainSettingsUpdated);
return Resource.SuccessfullySaveSettingsMessage;
}
@ -283,16 +280,16 @@ public class SettingsController : BaseSettingsController
}
[HttpPost("userquotasettings")]
public async Task<object> SaveUserQuotaSettingsAsync(UserQuotaSettingsRequestsDto inDto)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
public async Task<object> SaveUserQuotaSettingsAsync(UserQuotaSettingsRequestsDto inDto)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
await _settingsManager.SaveAsync(new TenantUserQuotaSettings { EnableUserQuota = inDto.EnableUserQuota, DefaultUserQuota = inDto.DefaultUserQuota });
await _settingsManager.SaveAsync(new TenantUserQuotaSettings { EnableUserQuota = inDto.EnableUserQuota, DefaultUserQuota = inDto.DefaultUserQuota });
return Resource.SuccessfullySaveSettingsMessage;
}
[AllowAnonymous]
[AllowAnonymous]
[AllowNotPayment]
[HttpGet("cultures")]
public IEnumerable<object> GetSupportedCultures()
@ -301,11 +298,11 @@ public class SettingsController : BaseSettingsController
}
[Authorize(AuthenticationSchemes = "confirm", Roles = "Wizard,Administrators")]
[HttpGet("timezones")]
[HttpGet("timezones")]
[AllowNotPayment]
public async Task<List<TimezonesRequestsDto>> GetTimeZonesAsyncAsync()
public async Task<List<TimezonesRequestsDto>> GetTimeZonesAsyncAsync()
{
await ApiContext.AuthByClaimAsync();
await ApiContext.AuthByClaimAsync();
var timeZones = TimeZoneInfo.GetSystemTimeZones().ToList();
if (timeZones.All(tz => tz.Id != "UTC"))
@ -328,193 +325,193 @@ public class SettingsController : BaseSettingsController
}
[Authorize(AuthenticationSchemes = "confirm", Roles = "Wizard")]
[HttpGet("machine")]
[HttpGet("machine")]
[AllowNotPayment]
public object GetMachineName()
{
return Dns.GetHostName().ToLowerInvariant();
}
[HttpPut("dns")]
public async Task<object> SaveDnsSettingsAsync(DnsSettingsRequestsDto model)
{
return await _dnsSettings.SaveDnsSettingsAsync(model.DnsName, model.Enable);
}
}
[HttpPut("dns")]
public async Task<object> SaveDnsSettingsAsync(DnsSettingsRequestsDto model)
{
return await _dnsSettings.SaveDnsSettingsAsync(model.DnsName, model.Enable);
}
[HttpGet("recalculatequota")]
public async Task RecalculateQuotaAsync()
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
_quotaSyncOperation.RecalculateQuota(await _tenantManager.GetCurrentTenantAsync());
public async Task RecalculateQuotaAsync()
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
_quotaSyncOperation.RecalculateQuota(await _tenantManager.GetCurrentTenantAsync());
}
[HttpGet("checkrecalculatequota")]
public async Task<bool> CheckRecalculateQuotaAsync()
public async Task<bool> CheckRecalculateQuotaAsync()
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
return _quotaSyncOperation.CheckRecalculateQuota(await _tenantManager.GetCurrentTenantAsync());
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
return _quotaSyncOperation.CheckRecalculateQuota(await _tenantManager.GetCurrentTenantAsync());
}
[HttpGet("logo")]
public async Task<object> GetLogoAsync()
public async Task<object> GetLogoAsync()
{
return await _tenantInfoSettingsHelper.GetAbsoluteCompanyLogoPathAsync(await _settingsManager.LoadAsync<TenantInfoSettings>());
return await _tenantInfoSettingsHelper.GetAbsoluteCompanyLogoPathAsync(await _settingsManager.LoadAsync<TenantInfoSettings>());
}
[AllowNotPayment]
[HttpPut("wizard/complete")]
[Authorize(AuthenticationSchemes = "confirm", Roles = "Wizard")]
public async Task<WizardSettings> CompleteWizardAsync(WizardRequestsDto inDto)
{
await ApiContext.AuthByClaimAsync();
public async Task<WizardSettings> CompleteWizardAsync(WizardRequestsDto inDto)
{
await ApiContext.AuthByClaimAsync();
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
return await _firstTimeTenantSettings.SaveDataAsync(inDto);
return await _firstTimeTenantSettings.SaveDataAsync(inDto);
}
///<visible>false</visible>
[HttpPut("welcome/close")]
public async Task CloseWelcomePopupAsync()
public async Task CloseWelcomePopupAsync()
{
var currentUser = await _userManager.GetUsersAsync(_authContext.CurrentAccount.ID);
var currentUser = await _userManager.GetUsersAsync(_authContext.CurrentAccount.ID);
var collaboratorPopupSettings = await _settingsManager.LoadForCurrentUserAsync<CollaboratorSettings>();
var collaboratorPopupSettings = await _settingsManager.LoadForCurrentUserAsync<CollaboratorSettings>();
if (!(await _userManager.IsUserAsync(currentUser) && collaboratorPopupSettings.FirstVisit && !await _userManager.IsOutsiderAsync(currentUser)))
if (!(await _userManager.IsUserAsync(currentUser) && collaboratorPopupSettings.FirstVisit && !await _userManager.IsOutsiderAsync(currentUser)))
{
throw new NotSupportedException("Not available.");
}
collaboratorPopupSettings.FirstVisit = false;
await _settingsManager.SaveForCurrentUserAsync(collaboratorPopupSettings);
await _settingsManager.SaveForCurrentUserAsync(collaboratorPopupSettings);
}
[AllowAnonymous, AllowNotPayment, AllowSuspended]
[HttpGet("colortheme")]
public async Task<CustomColorThemesSettingsDto> GetColorThemeAsync()
{
return new CustomColorThemesSettingsDto(await _settingsManager.LoadAsync<CustomColorThemesSettings>(), _customColorThemesSettingsHelper.Limit);
}
public async Task<CustomColorThemesSettingsDto> GetColorThemeAsync()
{
return new CustomColorThemesSettingsDto(await _settingsManager.LoadAsync<CustomColorThemesSettings>(), _customColorThemesSettingsHelper.Limit);
}
[HttpPut("colortheme")]
public async Task<CustomColorThemesSettingsDto> SaveColorThemeAsync(CustomColorThemesSettingsRequestsDto inDto)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
var settings = await _settingsManager.LoadAsync<CustomColorThemesSettings>();
if (inDto.Theme != null)
{
try
{
await _semaphore.WaitAsync();
var theme = inDto.Theme;
if (CustomColorThemesSettingsItem.Default.Any(r => r.Id == theme.Id))
{
theme.Id = 0;
}
var settingItem = settings.Themes.SingleOrDefault(r => r.Id == theme.Id);
if (settingItem != null)
{
if (theme.Main != null)
{
settingItem.Main = new CustomColorThemesSettingsColorItem
{
Accent = theme.Main.Accent,
Buttons = theme.Main.Buttons
};
}
if (theme.Text != null)
{
settingItem.Text = new CustomColorThemesSettingsColorItem
{
Accent = theme.Text.Accent,
Buttons = theme.Text.Buttons
};
}
}
else
{
if (_customColorThemesSettingsHelper.Limit == 0 || settings.Themes.Count < _customColorThemesSettingsHelper.Limit)
{
if (theme.Id == 0)
{
theme.Id = settings.Themes.Max(r => r.Id) + 1;
}
theme.Name = "";
settings.Themes = settings.Themes.Append(theme).ToList();
}
}
await _settingsManager.SaveAsync(settings);
}
catch
{
throw;
}
finally
{
_semaphore.Release();
}
}
if (inDto.Selected.HasValue && settings.Themes.Any(r => r.Id == inDto.Selected.Value))
{
settings.Selected = inDto.Selected.Value;
await _settingsManager.SaveAsync(settings);
await _messageService.SendAsync(MessageAction.ColorThemeChanged);
}
public async Task<CustomColorThemesSettingsDto> SaveColorThemeAsync(CustomColorThemesSettingsRequestsDto inDto)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
var settings = await _settingsManager.LoadAsync<CustomColorThemesSettings>();
if (inDto.Theme != null)
{
try
{
await _semaphore.WaitAsync();
var theme = inDto.Theme;
if (CustomColorThemesSettingsItem.Default.Any(r => r.Id == theme.Id))
{
theme.Id = 0;
}
var settingItem = settings.Themes.SingleOrDefault(r => r.Id == theme.Id);
if (settingItem != null)
{
if (theme.Main != null)
{
settingItem.Main = new CustomColorThemesSettingsColorItem
{
Accent = theme.Main.Accent,
Buttons = theme.Main.Buttons
};
}
if (theme.Text != null)
{
settingItem.Text = new CustomColorThemesSettingsColorItem
{
Accent = theme.Text.Accent,
Buttons = theme.Text.Buttons
};
}
}
else
{
if (_customColorThemesSettingsHelper.Limit == 0 || settings.Themes.Count < _customColorThemesSettingsHelper.Limit)
{
if (theme.Id == 0)
{
theme.Id = settings.Themes.Max(r => r.Id) + 1;
}
theme.Name = "";
settings.Themes = settings.Themes.Append(theme).ToList();
}
}
await _settingsManager.SaveAsync(settings);
}
catch
{
throw;
}
finally
{
_semaphore.Release();
}
}
if (inDto.Selected.HasValue && settings.Themes.Any(r => r.Id == inDto.Selected.Value))
{
settings.Selected = inDto.Selected.Value;
await _settingsManager.SaveAsync(settings);
await _messageService.SendAsync(MessageAction.ColorThemeChanged);
}
return new CustomColorThemesSettingsDto(settings, _customColorThemesSettingsHelper.Limit);
}
}
[HttpDelete("colortheme")]
public async Task<CustomColorThemesSettingsDto> DeleteColorThemeAsync(int id)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
var settings = await _settingsManager.LoadAsync<CustomColorThemesSettings>();
if (CustomColorThemesSettingsItem.Default.Any(r => r.Id == id))
{
return new CustomColorThemesSettingsDto(settings, _customColorThemesSettingsHelper.Limit);
}
settings.Themes = settings.Themes.Where(r => r.Id != id).ToList();
if (settings.Selected == id)
{
settings.Selected = settings.Themes.Min(r => r.Id);
await _messageService.SendAsync(MessageAction.ColorThemeChanged);
}
await _settingsManager.SaveAsync(settings);
public async Task<CustomColorThemesSettingsDto> DeleteColorThemeAsync(int id)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
var settings = await _settingsManager.LoadAsync<CustomColorThemesSettings>();
if (CustomColorThemesSettingsItem.Default.Any(r => r.Id == id))
{
return new CustomColorThemesSettingsDto(settings, _customColorThemesSettingsHelper.Limit);
}
settings.Themes = settings.Themes.Where(r => r.Id != id).ToList();
if (settings.Selected == id)
{
settings.Selected = settings.Themes.Min(r => r.Id);
await _messageService.SendAsync(MessageAction.ColorThemeChanged);
}
await _settingsManager.SaveAsync(settings);
return new CustomColorThemesSettingsDto(settings, _customColorThemesSettingsHelper.Limit);
}
[HttpPut("closeadminhelper")]
public async Task CloseAdminHelperAsync()
{
if (!await _userManager.IsDocSpaceAdminAsync(_authContext.CurrentAccount.ID) || _coreBaseSettings.CustomMode || !_coreBaseSettings.Standalone)
{
throw new NotSupportedException("Not available.");
}
var adminHelperSettings = await _settingsManager.LoadForCurrentUserAsync<AdminHelperSettings>();
adminHelperSettings.Viewed = true;
await _settingsManager.SaveForCurrentUserAsync(adminHelperSettings);
}
}
[HttpPut("closeadminhelper")]
public async Task CloseAdminHelperAsync()
{
if (!await _userManager.IsDocSpaceAdminAsync(_authContext.CurrentAccount.ID) || _coreBaseSettings.CustomMode || !_coreBaseSettings.Standalone)
{
throw new NotSupportedException("Not available.");
}
var adminHelperSettings = await _settingsManager.LoadForCurrentUserAsync<AdminHelperSettings>();
adminHelperSettings.Viewed = true;
await _settingsManager.SaveForCurrentUserAsync(adminHelperSettings);
}
///<visible>false</visible>
[HttpPut("timeandlanguage")]
public async Task<object> TimaAndLanguageAsync(SettingsRequestsDto inDto)
public async Task<object> TimaAndLanguageAsync(SettingsRequestsDto inDto)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
var culture = CultureInfo.GetCultureInfo(inDto.Lng);
@ -536,47 +533,47 @@ public class SettingsController : BaseSettingsController
}
Tenant.TimeZone = timeZones.FirstOrDefault(tz => tz.Id == inDto.TimeZoneID)?.Id ?? TimeZoneInfo.Utc.Id;
await _tenantManager.SaveTenantAsync(Tenant);
await _tenantManager.SaveTenantAsync(Tenant);
if (!Tenant.TimeZone.Equals(oldTimeZone) || changelng)
{
if (!Tenant.TimeZone.Equals(oldTimeZone))
{
await _messageService.SendAsync(MessageAction.TimeZoneSettingsUpdated);
await _messageService.SendAsync(MessageAction.TimeZoneSettingsUpdated);
}
if (changelng)
{
await _messageService.SendAsync(MessageAction.LanguageSettingsUpdated);
await _messageService.SendAsync(MessageAction.LanguageSettingsUpdated);
}
}
return Resource.SuccessfullySaveSettingsMessage;
}
}
///<visible>false</visible>
[HttpPut("defaultpage")]
public async Task<object> SaveDefaultPageSettingAsync(SettingsRequestsDto inDto)
public async Task<object> SaveDefaultPageSettingAsync(SettingsRequestsDto inDto)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
await _settingsManager.SaveAsync(new StudioDefaultPageSettings { DefaultProductID = inDto.DefaultProductID });
await _settingsManager.SaveAsync(new StudioDefaultPageSettings { DefaultProductID = inDto.DefaultProductID });
await _messageService.SendAsync(MessageAction.DefaultStartPageSettingsUpdated);
await _messageService.SendAsync(MessageAction.DefaultStartPageSettingsUpdated);
return Resource.SuccessfullySaveSettingsMessage;
}
[HttpPut("emailactivation")]
public async Task<EmailActivationSettings> UpdateEmailActivationSettingsAsync(EmailActivationSettings settings)
public async Task<EmailActivationSettings> UpdateEmailActivationSettingsAsync(EmailActivationSettings settings)
{
await _settingsManager.SaveForCurrentUserAsync(settings);
await _settingsManager.SaveForCurrentUserAsync(settings);
return settings;
}
[HttpGet("statistics/spaceusage/{id}")]
public async Task<List<UsageSpaceStatItemDto>> GetSpaceUsageStatistics(Guid id)
public async Task<List<UsageSpaceStatItemDto>> GetSpaceUsageStatistics(Guid id)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
var webitem = _webItemManagerSecurity.GetItems(WebZoneType.All, ItemAvailableState.All)
.FirstOrDefault(item =>
@ -587,7 +584,7 @@ public class SettingsController : BaseSettingsController
if (webitem == null)
{
return new List<UsageSpaceStatItemDto>();
return new List<UsageSpaceStatItemDto>();
}
var statData = await webitem.Context.SpaceUsageStatManager.GetStatDataAsync();
@ -603,9 +600,9 @@ public class SettingsController : BaseSettingsController
}
[HttpGet("statistics/visit")]
public async Task<List<ChartPointDto>> GetVisitStatisticsAsync(ApiDateTime fromDate, ApiDateTime toDate)
public async Task<List<ChartPointDto>> GetVisitStatisticsAsync(ApiDateTime fromDate, ApiDateTime toDate)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
var from = _tenantUtil.DateTimeFromUtc(fromDate);
var to = _tenantUtil.DateTimeFromUtc(toDate);
@ -628,8 +625,8 @@ public class SettingsController : BaseSettingsController
});
}
var hits = await _statisticManager.GetHitsByPeriodAsync(Tenant.Id, from, to);
var hosts = await _statisticManager.GetHostsByPeriodAsync(Tenant.Id, from, to);
var hits = await _statisticManager.GetHitsByPeriodAsync(Tenant.Id, from, to);
var hosts = await _statisticManager.GetHostsByPeriodAsync(Tenant.Id, from, to);
if (hits.Count == 0 || hosts.Count == 0)
{
@ -689,11 +686,11 @@ public class SettingsController : BaseSettingsController
}
[HttpPost("authservice")]
public async Task<bool> SaveAuthKeys(AuthServiceRequestsDto inDto)
public async Task<bool> SaveAuthKeys(AuthServiceRequestsDto inDto)
{
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
var saveAvailable = _coreBaseSettings.Standalone || (await _tenantManager.GetTenantQuotaAsync(await _tenantManager.GetCurrentTenantIdAsync())).ThirdParty;
var saveAvailable = _coreBaseSettings.Standalone || (await _tenantManager.GetTenantQuotaAsync(await _tenantManager.GetCurrentTenantIdAsync())).ThirdParty;
if (!SetupInfo.IsVisibleSettings(nameof(ManagementType.ThirdPartyAuthorization))
|| !saveAvailable)
{
@ -701,25 +698,10 @@ public class SettingsController : BaseSettingsController
}
var changed = false;
var consumer = _consumerFactory.GetByKey<Consumer>(inDto.Name);
var consumer = _consumerFactory.GetByKey<Consumer>(inDto.Name);
var validateKeyProvider = consumer as IValidateKeysProvider;
if (validateKeyProvider != null)
{
try
{
if (validateKeyProvider is BitlyLoginProvider bitly)
{
_urlShortener.Instance = null;
}
}
catch (Exception e)
{
_log.ErrorSaveAuthKeys(e);
}
}
if (inDto.Props.All(r => string.IsNullOrEmpty(r.Value)))
{
consumer.Clear();
@ -739,7 +721,7 @@ public class SettingsController : BaseSettingsController
? consumer.ManagedKeys.All(key => string.IsNullOrEmpty(consumer[key]))
: consumer.All(r => string.IsNullOrEmpty(r.Value));
if (validateKeyProvider != null && !await validateKeyProvider.ValidateKeysAsync() && !allPropsIsEmpty)
if (validateKeyProvider != null && !await validateKeyProvider.ValidateKeysAsync() && !allPropsIsEmpty)
{
consumer.Clear();
throw new ArgumentException(Resource.ErrorBadKeys);
@ -747,24 +729,24 @@ public class SettingsController : BaseSettingsController
if (changed)
{
await _messageService.SendAsync(MessageAction.AuthorizationKeysSetting);
await _messageService.SendAsync(MessageAction.AuthorizationKeysSetting);
}
return changed;
}
}
[AllowNotPayment]
[HttpGet("payment")]
public async Task<object> PaymentSettingsAsync()
public async Task<object> PaymentSettingsAsync()
{
var settings = await _settingsManager.LoadForDefaultTenantAsync<AdditionalWhiteLabelSettings>();
var currentQuota = await _tenantManager.GetCurrentTenantQuotaAsync();
var currentTariff = await _tenantExtra.GetCurrentTariffAsync();
var settings = await _settingsManager.LoadForDefaultTenantAsync<AdditionalWhiteLabelSettings>();
var currentQuota = await _tenantManager.GetCurrentTenantQuotaAsync();
var currentTariff = await _tenantExtra.GetCurrentTariffAsync();
if (!int.TryParse(_configuration["core:payment:max-quantity"], out var maxQuotaQuantity))
{
maxQuotaQuantity = 999;
}
if (!int.TryParse(_configuration["core:payment:max-quantity"], out var maxQuotaQuantity))
{
maxQuotaQuantity = 999;
}
return
new
@ -777,7 +759,7 @@ public class SettingsController : BaseSettingsController
{
currentQuota.Trial,
currentTariff.DueDate.Date
},
},
max = maxQuotaQuantity
};
}
@ -809,17 +791,17 @@ public class SettingsController : BaseSettingsController
/// </summary>
/// <returns>0 - not connected, 1 - connected, 2 - awaiting confirmation</returns>
[HttpGet("telegramisconnected")]
public async Task<object> TelegramIsConnectedAsync()
public async Task<object> TelegramIsConnectedAsync()
{
return (int) await _telegramHelper.UserIsConnectedAsync(_authContext.CurrentAccount.ID, Tenant.Id);
return (int) await _telegramHelper.UserIsConnectedAsync(_authContext.CurrentAccount.ID, Tenant.Id);
}
/// <summary>
/// Unlinks TelegramBot from your account
/// </summary>
[HttpDelete("telegramdisconnect")]
public async Task TelegramDisconnectAsync()
public async Task TelegramDisconnectAsync()
{
await _telegramHelper.DisconnectAsync(_authContext.CurrentAccount.ID, Tenant.Id);
await _telegramHelper.DisconnectAsync(_authContext.CurrentAccount.ID, Tenant.Id);
}
}

View File

@ -44,6 +44,7 @@ public class Startup : BaseStartup
services.AddHostedService<LdapNotifyService>();
DIHelper.TryAdd<LdapNotifyService>();
}
services.AddBaseDbContextPool<FilesDbContext>();
services.AddBaseDbContextPool<BackupsContext>();
@ -73,5 +74,12 @@ public class Startup : BaseStartup
{
appBranch.UseAccountHandler();
});
app.MapWhen(
context => context.Request.Path.ToString().StartsWith(UrlShortRewriter.BasePath),
appBranch =>
{
appBranch.UseUrlShortRewriter();
});
}
}

View File

@ -0,0 +1,68 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Core;
public class UrlShortRewriter
{
public const string BasePath = "/sh/";
public UrlShortRewriter(RequestDelegate next)
{
}
public async Task InvokeAsync(HttpContext httpContext, IDbContextFactory<UrlShortenerDbContext> dbContextFactory)
{
var path = httpContext.Request.Path.ToString();
path = path.Substring(BasePath.Length);
var id = ShortUrl.Decode(path);
ShortLink link;
using (var context = dbContextFactory.CreateDbContext())
{
link = await context.ShortLinks.FindAsync(id);
}
if (link != null)
{
httpContext.Response.Redirect(link.Link);
}
else
{
throw new ArgumentException("Bad Request");
}
}
}
public static class UrlShortRewriterExtensions
{
public static IApplicationBuilder UseUrlShortRewriter(this IApplicationBuilder builder)
{
return builder.UseMiddleware<UrlShortRewriter>();
}
}

View File

@ -26,138 +26,144 @@
namespace ASC.Web.Core.Utility;
[Scope(Additional = typeof(UrlShortenerExtension))]
public interface IUrlShortener
{
Task<string> GetShortenLinkAsync(string shareLink);
}
[Scope]
public class UrlShortener
public class BaseUrlShortener: IUrlShortener
{
public bool Enabled { get { return Instance is not NullShortener; } }
private readonly ConsumerFactory _consumerFactory;
private readonly IServiceProvider _serviceProvider;
private IUrlShortener _instance;
public IUrlShortener Instance
public BaseUrlShortener(
ConsumerFactory consumerFactory,
IServiceProvider serviceProvider)
{
get
{
if (_instance == null)
{
if (_consumerFactory.Get<BitlyLoginProvider>().Enabled)
{
_instance = new BitLyShortener(_consumerFactory);
}
else if (!string.IsNullOrEmpty(_configuration["web:url-shortener:value"]))
{
_instance = new OnlyoShortener(_configuration, _commonLinkUtility, _machinePseudoKeys, _clientFactory);
}
else
{
_instance = new NullShortener();
}
}
return _instance;
}
set
{
_instance = value;
}
_consumerFactory = consumerFactory;
_serviceProvider = serviceProvider;
}
private readonly IConfiguration _configuration;
private readonly ConsumerFactory _consumerFactory;
private readonly CommonLinkUtility _commonLinkUtility;
private readonly MachinePseudoKeys _machinePseudoKeys;
private readonly IHttpClientFactory _clientFactory;
public UrlShortener(
IConfiguration configuration,
ConsumerFactory consumerFactory,
CommonLinkUtility commonLinkUtility,
MachinePseudoKeys machinePseudoKeys,
IHttpClientFactory clientFactory)
public Task<string> GetShortenLinkAsync(string shareLink)
{
_configuration = configuration;
_consumerFactory = consumerFactory;
_commonLinkUtility = commonLinkUtility;
_machinePseudoKeys = machinePseudoKeys;
_clientFactory = clientFactory;
IUrlShortener shortener;
if (_consumerFactory.Get<BitlyLoginProvider>().Enabled)
{
shortener = _serviceProvider.GetRequiredService<BitLyShortener>();
}
else
{
shortener = _serviceProvider.GetRequiredService<OnlyoShortener>();
}
return shortener.GetShortenLinkAsync(shareLink);
}
}
[Scope]
public class BitLyShortener : IUrlShortener
{
public BitLyShortener(ConsumerFactory consumerFactory)
{
ConsumerFactory = consumerFactory;
}
private ConsumerFactory ConsumerFactory { get; }
public Task<string> GetShortenLinkAsync(string shareLink)
{
return Task.FromResult(ConsumerFactory.Get<BitlyLoginProvider>().GetShortenLink(shareLink));
}
}
[Scope]
public class OnlyoShortener : IUrlShortener
{
private readonly string _url;
private readonly string _internalUrl;
private readonly byte[] _sKey;
private CommonLinkUtility CommonLinkUtility { get; }
private IHttpClientFactory ClientFactory { get; }
public OnlyoShortener(
IConfiguration configuration,
CommonLinkUtility commonLinkUtility,
MachinePseudoKeys machinePseudoKeys,
IHttpClientFactory clientFactory)
private readonly IDbContextFactory<UrlShortenerDbContext> _contextFactory;
private readonly CommonLinkUtility _commonLinkUtility;
public OnlyoShortener(IDbContextFactory<UrlShortenerDbContext> contextFactory,
CommonLinkUtility commonLinkUtility)
{
_url = configuration["web:url-shortener:value"];
_internalUrl = configuration["web:url-shortener:internal"];
_sKey = machinePseudoKeys.GetMachineConstant();
if (!_url.EndsWith('/'))
{
_url += '/';
}
CommonLinkUtility = commonLinkUtility;
ClientFactory = clientFactory;
_contextFactory = contextFactory;
_commonLinkUtility = commonLinkUtility;
}
public async Task<string> GetShortenLinkAsync(string shareLink)
{
var request = new HttpRequestMessage
if (Uri.IsWellFormedUriString(shareLink, UriKind.Absolute))
{
RequestUri = new Uri(_internalUrl + "?url=" + HttpUtility.UrlEncode(shareLink))
};
request.Headers.Add("Authorization", CreateAuthToken());
request.Headers.Add("Encoding", Encoding.UTF8.ToString());//todo check
var httpClient = ClientFactory.CreateClient();
using var response = await httpClient.SendAsync(request);
await using var stream = await response.Content.ReadAsStreamAsync();
using var rs = new StreamReader(stream);
return CommonLinkUtility.GetFullAbsolutePath(_url + await rs.ReadToEndAsync());
}
private string CreateAuthToken(string pkey = "urlShortener")
{
using var hasher = new HMACSHA1(_sKey);
var now = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
var hash = Convert.ToBase64String(hasher.ComputeHash(Encoding.UTF8.GetBytes(string.Join("\n", now, pkey))));
return $"ASC {pkey}:{now}:{hash}";
var context = _contextFactory.CreateDbContext();
var link = await context.ShortLinks.FirstOrDefaultAsync(q=> q.Link == shareLink);
if (link != null)
{
return _commonLinkUtility.GetFullAbsolutePath(UrlShortRewriter.BasePath + link.Short);
}
else
{
while (true)
{
var key = ShortUrl.GenerateRandomKey();
var id = ShortUrl.Decode(key);
var existId = await context.ShortLinks.AnyAsync(q => q.Id == id);
if (!existId)
{
var newShortLink = new ShortLink()
{
Id = id,
Link = shareLink,
Short = key
};
await context.ShortLinks.AddAsync(newShortLink);
await context.SaveChangesAsync();
return _commonLinkUtility.GetFullAbsolutePath(UrlShortRewriter.BasePath + key);
}
}
}
}
else
{
return shareLink;
}
}
}
public class NullShortener : IUrlShortener
public static class ShortUrl
{
public Task<string> GetShortenLinkAsync(string shareLink)
private const string Alphabet = "5XzpDt6wZRdsTrJkSY_cgPyxN4j-fnb9WKBF8vh3GH72QqmLVCM";
private static readonly int _base = Alphabet.Length;
public static string GenerateRandomKey()
{
return Task.FromResult<string>(null);
var rand = new Random();
var length = rand.Next(5, 8);
var result = "";
for (var i = 0; i < length; i++)
{
var x = rand.Next(0, 51);
result += Alphabet.ElementAt(x);
}
return result;
}
public static long Decode(string str)
{
long num = 0;
for (var i = 0; i < str.Length; i++)
{
num = num * _base + Alphabet.IndexOf(str.ElementAt(i));
}
return num;
}
}
public static class UrlShortenerExtension
{
public static void Register(DIHelper dIHelper)
{
dIHelper.TryAdd<IUrlShortener, BaseUrlShortener>();
dIHelper.TryAdd<BitLyShortener>();
dIHelper.TryAdd<OnlyoShortener>();
}
}