Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add upload options to reverse shares' shares #185

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dev": "cross-env NODE_ENV=development nest start --watch",
"prod": "prisma migrate deploy && prisma db seed && node dist/src/main",
"lint": "eslint 'src/**/*.ts'",
"format": "prettier --write 'src/**/*.ts'",
"format": "prettier --end-of-line=auto --write 'src/**/*.ts'",
"test:system": "prisma migrate reset -f && nest start & wait-on http://localhost:8080/api/configs && newman run ./test/newman-system-tests.json"
},
"prisma": {
Expand Down
stonith404 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- CreateTable
CREATE TABLE "ReverseShareOptions" (
"id" TEXT NOT NULL PRIMARY KEY,
"shareId" TEXT NOT NULL,
"easyMode" BOOLEAN NOT NULL DEFAULT false,
"customLinkEnabled" BOOLEAN NOT NULL DEFAULT true,
"passwordEnabled" BOOLEAN NOT NULL DEFAULT true,
"descriptionEnabled" BOOLEAN NOT NULL DEFAULT true,
"maximalViewsEnabled" BOOLEAN NOT NULL DEFAULT true,
CONSTRAINT "ReverseShareOptions_shareId_fkey" FOREIGN KEY ("shareId") REFERENCES "ReverseShare" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);

-- CreateIndex
CREATE UNIQUE INDEX "ReverseShareOptions_shareId_key" ON "ReverseShareOptions"("shareId");
14 changes: 14 additions & 0 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ model ReverseShare {
creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)

shares Share[]
sharesOptions ReverseShareOptions?
}

model ReverseShareOptions {
id String @id @default(uuid())
share ReverseShare @relation(fields: [shareId], references: [id], onDelete: Cascade)
shareId String @unique

easyMode Boolean @default(false)
pierrbt marked this conversation as resolved.
Show resolved Hide resolved

customLinkEnabled Boolean @default(true)
passwordEnabled Boolean @default(true)
descriptionEnabled Boolean @default(true)
maximalViewsEnabled Boolean @default(true)
}

model ShareRecipient {
Expand Down
12 changes: 8 additions & 4 deletions backend/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
export const DATA_DIRECTORY = process.env.DATA_DIRECTORY || "./data";
export const SHARE_DIRECTORY = `${DATA_DIRECTORY}/uploads/shares`
export const DATABASE_URL = process.env.DATABASE_URL || "file:../data/pingvin-share.db?connection_limit=1";
export const CLAMAV_HOST = process.env.CLAMAV_HOST || (process.env.NODE_ENV == "docker" ? "clamav" : "127.0.0.1");
export const CLAMAV_PORT = parseInt(process.env.CLAMAV_PORT) || 3310;
export const SHARE_DIRECTORY = `${DATA_DIRECTORY}/uploads/shares`;
export const DATABASE_URL =
process.env.DATABASE_URL ||
"file:../data/pingvin-share.db?connection_limit=1";
export const CLAMAV_HOST =
process.env.CLAMAV_HOST ||
(process.env.NODE_ENV == "docker" ? "clamav" : "127.0.0.1");
export const CLAMAV_PORT = parseInt(process.env.CLAMAV_PORT) || 3310;
15 changes: 15 additions & 0 deletions backend/src/reverseShare/dto/createReverseShare.dto.ts
stonith404 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ export class CreateReverseShareDTO {
@IsString()
shareExpiration: string;

@IsBoolean()
easyMode: boolean;

@IsBoolean()
customLinkEnabled: boolean;

@IsBoolean()
passwordEnabled: boolean;

@IsBoolean()
descriptionEnabled: boolean;

@IsBoolean()
maximalViewsEnabled: boolean;

@Min(1)
@Max(1000)
maxUseCount: number;
Expand Down
10 changes: 9 additions & 1 deletion backend/src/reverseShare/dto/reverseShare.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Expose, plainToClass } from "class-transformer";
import { Expose, plainToClass, Type } from "class-transformer";
import { ReverseShareOptionsDTO } from "./reverseShareOptions.dto";

export class ReverseShareDTO {
@Expose()
Expand All @@ -10,6 +11,13 @@ export class ReverseShareDTO {
@Expose()
shareExpiration: Date;

@Expose()
@Type(() => ReverseShareOptionsDTO)
sharesOptions: ReverseShareOptionsDTO;

@Expose()
token: string;

from(partial: Partial<ReverseShareDTO>) {
return plainToClass(ReverseShareDTO, partial, {
excludeExtraneousValues: true,
Expand Down
18 changes: 18 additions & 0 deletions backend/src/reverseShare/dto/reverseShareOptions.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Expose } from "class-transformer";

export class ReverseShareOptionsDTO {
@Expose()
easyMode: boolean;

@Expose()
customLinkEnabled: boolean;

@Expose()
passwordEnabled: boolean;

@Expose()
descriptionEnabled: boolean;

@Expose()
maximalViewsEnabled: boolean;
}
13 changes: 12 additions & 1 deletion backend/src/reverseShare/reverseShare.service.ts
stonith404 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ConfigService } from "src/config/config.service";
import { FileService } from "src/file/file.service";
import { PrismaService } from "src/prisma/prisma.service";
import { CreateReverseShareDTO } from "./dto/createReverseShare.dto";
import { connect } from "rxjs";
pierrbt marked this conversation as resolved.
Show resolved Hide resolved

@Injectable()
export class ReverseShareService {
Expand Down Expand Up @@ -36,6 +37,15 @@ export class ReverseShareService {
shareExpiration: expirationDate,
remainingUses: data.maxUseCount,
maxShareSize: data.maxShareSize,
sharesOptions: {
create: {
easyMode: data.easyMode,
customLinkEnabled: data.customLinkEnabled,
passwordEnabled: data.passwordEnabled,
descriptionEnabled: data.descriptionEnabled,
maximalViewsEnabled: data.maximalViewsEnabled,
},
},
sendEmailNotification: data.sendEmailNotification,
creatorId,
},
Expand All @@ -49,6 +59,7 @@ export class ReverseShareService {

const reverseShare = await this.prisma.reverseShare.findUnique({
where: { token: reverseShareToken },
include: { sharesOptions: true, shares: { include: { creator: true } } },
});

return reverseShare;
Expand All @@ -63,7 +74,7 @@ export class ReverseShareService {
orderBy: {
shareExpiration: "desc",
},
include: { shares: { include: { creator: true } } },
include: { sharesOptions: true, shares: { include: { creator: true } } },
});

return reverseShares;
Expand Down
6 changes: 3 additions & 3 deletions backend/src/share/dto/myShare.dto.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Expose, plainToClass, Type } from "class-transformer";
import { ShareDTO } from "./share.dto";
import {FileDTO} from "../../file/dto/file.dto";
import {OmitType} from "@nestjs/swagger";
import { FileDTO } from "../../file/dto/file.dto";
import { OmitType } from "@nestjs/swagger";

export class MyShareDTO extends OmitType(ShareDTO, [
"files",
Expand Down Expand Up @@ -30,4 +30,4 @@ export class MyShareDTO extends OmitType(ShareDTO, [
plainToClass(MyShareDTO, part, { excludeExtraneousValues: true })
);
}
}
}
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"build": "next build",
"start": "next start",
"lint": "next lint",
"format": "prettier --write \"src/**/*.ts*\""
"format": "prettier --end-of-line=auto --write \"src/**/*.ts*\""
},
"dependencies": {
"@emotion/react": "^11.10.6",
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/components/account/showReverseShareLinkModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Stack, TextInput } from "@mantine/core";
import { ModalsContextProps } from "@mantine/modals/lib/context";

const showReverseShareLinkModal = (
modals: ModalsContextProps,
reverseShareToken: string,
appUrl: string
) => {
const link = `${appUrl}/upload/${reverseShareToken}`;
return modals.openModal({
title: "Reverse share link",
children: (
<Stack align="stretch">
<TextInput variant="filled" value={link} />
</Stack>
),
});
};

export default showReverseShareLinkModal;
stonith404 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
Accordion,
Button,
Checkbox,
Col,
Grid,
Group,
Expand All @@ -8,6 +10,7 @@ import {
Stack,
Switch,
Text,
Textarea,
pierrbt marked this conversation as resolved.
Show resolved Hide resolved
} from "@mantine/core";
import { useForm } from "@mantine/form";
import { useModals } from "@mantine/modals";
Expand Down Expand Up @@ -50,6 +53,12 @@ const Body = ({
sendEmailNotification: false,
expiration_num: 1,
expiration_unit: "-days",

easyMode: false,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment about easyMode. If we remove easyMode the file would need to have a refactor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you're right, but is it necessary ? Your choice

customLinkEnabled: true,
passwordEnabled: false,
descriptionEnabled: false,
maximalViewsEnabled: false,
},
});
return (
Expand All @@ -61,7 +70,14 @@ const Body = ({
values.expiration_num + values.expiration_unit,
values.maxShareSize,
values.maxUseCount,
values.sendEmailNotification
values.sendEmailNotification,
{
easyMode: values.easyMode,
customLinkEnabled: values.customLinkEnabled,
passwordEnabled: values.passwordEnabled,
descriptionEnabled: values.descriptionEnabled,
maximalViewsEnabled: values.maximalViewsEnabled,
}
)
.then(({ link }) => {
modals.closeAll();
Expand Down Expand Up @@ -154,6 +170,54 @@ const Body = ({
/>
)}

<Accordion>
<Accordion.Item value="shareOptions" sx={{ borderBottom: "none" }}>
<Accordion.Control>Share options</Accordion.Control>
<Accordion.Panel>
<Stack align="stretch">
<Checkbox
label="Easy mode"
description="Disable all options"
{...form.getInputProps("easyMode", { type: "checkbox" })}
/>

{!form.values.easyMode && (
<Stack>
<Checkbox
label="Custom link"
description="Allow the user to set a custom link"
{...form.getInputProps("customLinkEnabled", {
type: "checkbox",
})}
/>
<Checkbox
label="Password"
description="Possibility to add a password to access the share"
{...form.getInputProps("passwordEnabled", {
type: "checkbox",
})}
/>
<Checkbox
label="Description"
description="Add a description to the share"
{...form.getInputProps("descriptionEnabled", {
type: "checkbox",
})}
/>
<Checkbox
label="Maximal views"
description="Set a maximal number of views for the share"
{...form.getInputProps("maximalViewsEnabled", {
type: "checkbox",
})}
/>
</Stack>
)}
</Stack>
</Accordion.Panel>
</Accordion.Item>
</Accordion>

<Button mt="md" type="submit">
Create
</Button>
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/upload/CopyTextField.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useRef, useState } from "react";
import toast from "../../utils/toast.util";
import { ActionIcon, TextInput } from "@mantine/core";
import { TbCheck, TbCopy } from "react-icons/tb";
import { useClipboard } from "@mantine/hooks";
import { useRef, useState } from "react";
import { TbCheck, TbCopy } from "react-icons/tb";
import toast from "../../utils/toast.util";

function CopyTextField(props: { link: string }) {
const clipboard = useClipboard({ timeout: 500 });
Expand All @@ -14,7 +14,7 @@ function CopyTextField(props: { link: string }) {

const copyLink = () => {
clipboard.copy(props.link);
toast.success("Your link was copied to the keyboard.");
toast.success("The link was copied to your clipboard.");
if (timerRef.current) clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
setCheckState(false);
Expand Down
Loading