Compare commits

..

3 Commits

Author SHA1 Message Date
Elias Schneider
7f9f8b6fe7 release: 1.8.1 2025-01-04 01:28:23 +01:00
Elias Schneider
bf1b2633c8 refactor: run formatter 2025-01-04 01:28:05 +01:00
Elias Schneider
b3ea96c191 fix: wrong validation for expiration in reverse share modal 2025-01-04 01:27:59 +01:00
18 changed files with 131 additions and 103 deletions

View File

@@ -1,3 +1,10 @@
## [1.8.1](https://github.com/stonith404/pingvin-share/compare/v1.8.0...v1.8.1) (2025-01-04)
### Bug Fixes
* wrong validation for expiration in reverse share modal ([b3ea96c](https://github.com/stonith404/pingvin-share/commit/b3ea96c1916980863fc6903c64cd2a7b32d66cfb))
## [1.8.0](https://github.com/stonith404/pingvin-share/compare/v1.7.2...v1.8.0) (2025-01-02) ## [1.8.0](https://github.com/stonith404/pingvin-share/compare/v1.7.2...v1.8.0) (2025-01-02)

View File

@@ -1,12 +1,12 @@
{ {
"name": "pingvin-share-backend", "name": "pingvin-share-backend",
"version": "1.8.0", "version": "1.8.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pingvin-share-backend", "name": "pingvin-share-backend",
"version": "1.8.0", "version": "1.8.1",
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.679.0", "@aws-sdk/client-s3": "^3.679.0",
"@nestjs/cache-manager": "^2.2.2", "@nestjs/cache-manager": "^2.2.2",

View File

@@ -1,6 +1,6 @@
{ {
"name": "pingvin-share-backend", "name": "pingvin-share-backend",
"version": "1.8.0", "version": "1.8.1",
"scripts": { "scripts": {
"build": "nest build", "build": "nest build",
"dev": "cross-env NODE_ENV=development nest start --watch", "dev": "cross-env NODE_ENV=development nest start --watch",

View File

@@ -345,7 +345,9 @@ export class AuthService {
if (refreshToken) { if (refreshToken) {
const now = moment(); const now = moment();
const sessionDuration = this.config.get("general.sessionDuration"); const sessionDuration = this.config.get("general.sessionDuration");
const maxAge = moment(now).add(sessionDuration.value, sessionDuration.unit).diff(now); const maxAge = moment(now)
.add(sessionDuration.value, sessionDuration.unit)
.diff(now);
response.cookie("refresh_token", refreshToken, { response.cookie("refresh_token", refreshToken, {
path: "/api/auth/token", path: "/api/auth/token",
httpOnly: true, httpOnly: true,

View File

@@ -36,8 +36,7 @@ export class ConfigService extends EventEmitter {
if (configVariable.type == "boolean") return value == "true"; if (configVariable.type == "boolean") return value == "true";
if (configVariable.type == "string" || configVariable.type == "text") if (configVariable.type == "string" || configVariable.type == "text")
return value; return value;
if (configVariable.type == "timespan") if (configVariable.type == "timespan") return stringToTimespan(value);
return stringToTimespan(value);
} }
async getByCategory(category: string) { async getByCategory(category: string) {

View File

@@ -26,10 +26,11 @@ export class ReverseShareService {
.toDate(); .toDate();
const parsedExpiration = parseRelativeDateToAbsolute(data.shareExpiration); const parsedExpiration = parseRelativeDateToAbsolute(data.shareExpiration);
const maxExpiration = this.config.get("share.maxExpiration");
if ( if (
this.config.get("share.maxExpiration") !== 0 && maxExpiration.value !== 0 &&
parsedExpiration > parsedExpiration >
moment().add(this.config.get("share.maxExpiration"), "hours").toDate() moment().add(maxExpiration.value, maxExpiration.unit).toDate()
) { ) {
throw new BadRequestException( throw new BadRequestException(
"Expiration date exceeds maximum expiration date", "Expiration date exceeds maximum expiration date",

View File

@@ -61,9 +61,7 @@ export class ShareService {
maxExpiration.value !== 0 && maxExpiration.value !== 0 &&
(expiresNever || (expiresNever ||
parsedExpiration > parsedExpiration >
moment() moment().add(maxExpiration.value, maxExpiration.unit).toDate())
.add(maxExpiration.value, maxExpiration.unit)
.toDate())
) { ) {
throw new BadRequestException( throw new BadRequestException(
"Expiration date exceeds maximum expiration date", "Expiration date exceeds maximum expiration date",

View File

@@ -1,12 +1,12 @@
{ {
"name": "pingvin-share-frontend", "name": "pingvin-share-frontend",
"version": "1.8.0", "version": "1.8.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pingvin-share-frontend", "name": "pingvin-share-frontend",
"version": "1.8.0", "version": "1.8.1",
"dependencies": { "dependencies": {
"@emotion/react": "^11.13.3", "@emotion/react": "^11.13.3",
"@emotion/server": "^11.11.0", "@emotion/server": "^11.11.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "pingvin-share-frontend", "name": "pingvin-share-frontend",
"version": "1.8.0", "version": "1.8.1",
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",

View File

@@ -96,7 +96,9 @@ const AdminConfigInput = ({
{configVariable.type == "timespan" && ( {configVariable.type == "timespan" && (
<TimespanInput <TimespanInput
value={stringToTimespan(configVariable.value)} value={stringToTimespan(configVariable.value)}
onChange={(timespan) => onValueChange(configVariable, timespanToString(timespan))} onChange={(timespan) =>
onValueChange(configVariable, timespanToString(timespan))
}
w={201} w={201}
/> />
)} )}

View File

@@ -3,81 +3,86 @@ import { Timespan } from "../../types/timespan.type";
import { NativeSelect, NumberInput } from "@mantine/core"; import { NativeSelect, NumberInput } from "@mantine/core";
import useTranslate from "../../hooks/useTranslate.hook"; import useTranslate from "../../hooks/useTranslate.hook";
const TimespanInput = ({ label, value, onChange, ...restProps }: { const TimespanInput = ({
label?: string, label,
value: Timespan, value,
onChange: (timespan: Timespan) => void, onChange,
[key: string]: any, ...restProps
}: {
label?: string;
value: Timespan;
onChange: (timespan: Timespan) => void;
[key: string]: any;
}) => { }) => {
const [unit, setUnit] = useState(value.unit); const [unit, setUnit] = useState(value.unit);
const [inputValue, setInputValue] = useState(value.value); const [inputValue, setInputValue] = useState(value.value);
const t = useTranslate(); const t = useTranslate();
const version = inputValue == 1 ? "singular" : "plural";
const unitSelect = (
<NativeSelect
data={[
{
value: "minutes",
label: t(`upload.modal.expires.minute-${version}`),
},
{
value: "hours",
label: t(`upload.modal.expires.hour-${version}`),
},
{
value: "days",
label: t(`upload.modal.expires.day-${version}`),
},
{
value: "weeks",
label: t(`upload.modal.expires.week-${version}`),
},
{
value: "months",
label: t(`upload.modal.expires.month-${version}`),
},
{
value: "years",
label: t(`upload.modal.expires.year-${version}`),
},
]}
value={unit}
rightSectionWidth={28}
styles={{
input: {
fontWeight: 500,
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
width: 120,
marginRight: -2,
},
}}
onChange={event => {
const unit = event.currentTarget.value as Timespan["unit"];
setUnit(unit);
onChange({ value: inputValue, unit });
}}
/>
);
return ( const version = inputValue == 1 ? "singular" : "plural";
<NumberInput const unitSelect = (
label={label} <NativeSelect
value={inputValue} data={[
min={0} {
max={999999} value: "minutes",
precision={0} label: t(`upload.modal.expires.minute-${version}`),
rightSection={unitSelect} },
rightSectionWidth={120} {
onChange={value => { value: "hours",
const inputVal = value || 0; label: t(`upload.modal.expires.hour-${version}`),
setInputValue(inputVal); },
onChange({ value: inputVal, unit }); {
}} value: "days",
{...restProps} label: t(`upload.modal.expires.day-${version}`),
/> },
); {
value: "weeks",
label: t(`upload.modal.expires.week-${version}`),
},
{
value: "months",
label: t(`upload.modal.expires.month-${version}`),
},
{
value: "years",
label: t(`upload.modal.expires.year-${version}`),
},
]}
value={unit}
rightSectionWidth={28}
styles={{
input: {
fontWeight: 500,
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
width: 120,
marginRight: -2,
},
}}
onChange={(event) => {
const unit = event.currentTarget.value as Timespan["unit"];
setUnit(unit);
onChange({ value: inputValue, unit });
}}
/>
);
return (
<NumberInput
label={label}
value={inputValue}
min={0}
max={999999}
precision={0}
rightSection={unitSelect}
rightSectionWidth={120}
onChange={(value) => {
const inputVal = value || 0;
setInputValue(inputVal);
onChange({ value: inputVal, unit });
}}
{...restProps}
/>
);
}; };
export default TimespanInput; export default TimespanInput;

View File

@@ -20,6 +20,7 @@ import useTranslate, {
translateOutsideContext, translateOutsideContext,
} from "../../../hooks/useTranslate.hook"; } from "../../../hooks/useTranslate.hook";
import shareService from "../../../services/share.service"; import shareService from "../../../services/share.service";
import { Timespan } from "../../../types/timespan.type";
import { getExpirationPreview } from "../../../utils/date.util"; import { getExpirationPreview } from "../../../utils/date.util";
import toast from "../../../utils/toast.util"; import toast from "../../../utils/toast.util";
import FileSizeInput from "../../core/FileSizeInput"; import FileSizeInput from "../../core/FileSizeInput";
@@ -28,7 +29,7 @@ import showCompletedReverseShareModal from "./showCompletedReverseShareModal";
const showCreateReverseShareModal = ( const showCreateReverseShareModal = (
modals: ModalsContextProps, modals: ModalsContextProps,
showSendEmailNotificationOption: boolean, showSendEmailNotificationOption: boolean,
maxExpirationInHours: number, maxExpiration: Timespan,
getReverseShares: () => void, getReverseShares: () => void,
) => { ) => {
const t = translateOutsideContext(); const t = translateOutsideContext();
@@ -38,7 +39,7 @@ const showCreateReverseShareModal = (
<Body <Body
showSendEmailNotificationOption={showSendEmailNotificationOption} showSendEmailNotificationOption={showSendEmailNotificationOption}
getReverseShares={getReverseShares} getReverseShares={getReverseShares}
maxExpirationInHours={maxExpirationInHours} maxExpiration={maxExpiration}
/> />
), ),
}); });
@@ -47,12 +48,13 @@ const showCreateReverseShareModal = (
const Body = ({ const Body = ({
getReverseShares, getReverseShares,
showSendEmailNotificationOption, showSendEmailNotificationOption,
maxExpirationInHours, maxExpiration,
}: { }: {
getReverseShares: () => void; getReverseShares: () => void;
showSendEmailNotificationOption: boolean; showSendEmailNotificationOption: boolean;
maxExpirationInHours: number; maxExpiration: Timespan;
}) => { }) => {
console.log(maxExpiration);
const modals = useModals(); const modals = useModals();
const t = useTranslate(); const t = useTranslate();
@@ -91,13 +93,17 @@ const Body = ({
) as moment.unitOfTime.DurationConstructor, ) as moment.unitOfTime.DurationConstructor,
); );
if ( if (
maxExpirationInHours != 0 && maxExpiration.value != 0 &&
expirationDate.isAfter(moment().add(maxExpirationInHours, "hours")) expirationDate.isAfter(
moment().add(maxExpiration.value, maxExpiration.unit),
)
) { ) {
form.setFieldError( form.setFieldError(
"expiration_num", "expiration_num",
t("upload.modal.expires.error.too-long", { t("upload.modal.expires.error.too-long", {
max: moment.duration(maxExpirationInHours, "hours").humanize(), max: moment
.duration(maxExpiration.value, maxExpiration.unit)
.humanize(),
}), }),
); );
return; return;

View File

@@ -184,7 +184,10 @@ const CreateUploadModalBody = ({
options.maxExpiration.value != 0 && options.maxExpiration.value != 0 &&
(form.values.never_expires || (form.values.never_expires ||
expirationDate.isAfter( expirationDate.isAfter(
moment().add(options.maxExpiration.value, options.maxExpiration.unit), moment().add(
options.maxExpiration.value,
options.maxExpiration.unit,
),
)) ))
) { ) {
form.setFieldError( form.setFieldError(

View File

@@ -31,8 +31,7 @@ const get = (key: string, configVariables: Config[]): any => {
if (configVariable.type == "boolean") return value == "true"; if (configVariable.type == "boolean") return value == "true";
if (configVariable.type == "string" || configVariable.type == "text") if (configVariable.type == "string" || configVariable.type == "text")
return value; return value;
if (configVariable.type == "timespan") if (configVariable.type == "timespan") return stringToTimespan(value);
return stringToTimespan(value);
}; };
const finishSetup = async (): Promise<AdminConfig[]> => { const finishSetup = async (): Promise<AdminConfig[]> => {

View File

@@ -1,2 +1,8 @@
export type TimeUnit = "minutes" | "hours" | "days" | "weeks" | "months" | "years"; export type TimeUnit =
| "minutes"
| "hours"
| "days"
| "weeks"
| "months"
| "years";
export type Timespan = { value: number; unit: TimeUnit }; export type Timespan = { value: number; unit: TimeUnit };

View File

@@ -34,7 +34,7 @@ export const getExpirationPreview = (
export const timespanToString = (timespan: Timespan) => { export const timespanToString = (timespan: Timespan) => {
return `${timespan.value} ${timespan.unit}`; return `${timespan.value} ${timespan.unit}`;
} };
export const stringToTimespan = (value: string): Timespan => { export const stringToTimespan = (value: string): Timespan => {
return { return {

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "pingvin-share", "name": "pingvin-share",
"version": "1.8.0", "version": "1.8.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pingvin-share", "name": "pingvin-share",
"version": "1.8.0", "version": "1.8.1",
"devDependencies": { "devDependencies": {
"conventional-changelog-cli": "^3.0.0" "conventional-changelog-cli": "^3.0.0"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "pingvin-share", "name": "pingvin-share",
"version": "1.8.0", "version": "1.8.1",
"scripts": { "scripts": {
"format": "cd frontend && npm run format && cd ../backend && npm run format", "format": "cd frontend && npm run format && cd ../backend && npm run format",
"lint": "cd frontend && npm run lint && cd ../backend && npm run lint", "lint": "cd frontend && npm run lint && cd ../backend && npm run lint",