diff options
author | zzwt <loophone@gmail.com> | 2021-12-03 04:56:07 +0300 |
---|---|---|
committer | zzwt <loophone@gmail.com> | 2021-12-03 04:56:07 +0300 |
commit | 9cbbade1aee3a42406141a7fdb9e56edbdb7de62 (patch) | |
tree | 3387d4e20f7ed22acc35a1834d2298a1c00b2130 | |
parent | 0bc0e6629ba7d14bbe1ef0857ca9caf7110e953c (diff) |
feat: change link password
-rw-r--r-- | client/components/LinksTable.tsx | 38 | ||||
-rw-r--r-- | server/handlers/links.ts | 6 | ||||
-rw-r--r-- | server/handlers/validators.ts | 7 | ||||
-rw-r--r-- | server/queries/link.ts | 5 |
4 files changed, 49 insertions, 7 deletions
diff --git a/client/components/LinksTable.tsx b/client/components/LinksTable.tsx index f1b2a26..0759ec0 100644 --- a/client/components/LinksTable.tsx +++ b/client/components/LinksTable.tsx @@ -116,6 +116,7 @@ interface EditForm { address: string; description?: string; expire_in?: string; + password?: string; } const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => { @@ -123,7 +124,7 @@ const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => { const ban = useStoreActions(s => s.links.ban); const edit = useStoreActions(s => s.links.edit); const [banFormState, { checkbox }] = useFormState<BanForm>(); - const [editFormState, { text, label }] = useFormState<EditForm>( + const [editFormState, { text, label, password }] = useFormState<EditForm>( { target: link.target, address: link.address, @@ -132,7 +133,8 @@ const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => { ? ms(differenceInMilliseconds(new Date(link.expire_in), new Date()), { long: true }) - : "" + : "", + password: "" }, { withIds: true } ); @@ -175,6 +177,7 @@ const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => { } catch (err) { setEditMessage(errorMessage(err)); } + editFormState.setField("password", ""); setEditLoading(false); }; @@ -355,7 +358,7 @@ const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => { /> </Flex> </Col> - <Col alignItems="flex-start"> + <Col alignItems="flex-start" mr={3}> <Text {...label("address")} as="label" @@ -379,6 +382,33 @@ const Row: FC<RowProps> = ({ index, link, setDeleteModal }) => { /> </Flex> </Col> + <Col alignItems="flex-start"> + <Text + {...label("password")} + as="label" + mb={2} + fontSize={[14, 15]} + bold + > + Password + </Text> + <Flex as="form"> + <TextInput + {...password({ + name: "password" + })} + placeholder={link.password ? "●●●●●●●" : "Password..."} + autocomplete="off" + data-lpignore + pl={[3, 24]} + pr={[3, 24]} + placeholderSize={[13, 14]} + fontSize={[14, 15]} + height={[40, 44]} + width={[1, 210, 240]} + /> + </Flex> + </Col> </Flex> <Flex alignItems="flex-start" width={1} mt={3}> <Col alignItems="flex-start" mr={3}> @@ -613,7 +643,7 @@ const LinksTable: FC = () => { <H2 mb={3} light> Recent shortened links. </H2> - <Table scrollWidth="800px"> + <Table scrollWidth="1000px"> <thead> <Tr justifyContent="space-between"> <Th flexGrow={1} flexShrink={1}> diff --git a/server/handlers/links.ts b/server/handlers/links.ts index a497cdd..857c857 100644 --- a/server/handlers/links.ts +++ b/server/handlers/links.ts @@ -108,8 +108,7 @@ export const create: Handler = async (req: CreateLinkReq, res) => { }; export const edit: Handler = async (req, res) => { - const { address, target, description, expire_in } = req.body; - + const { address, target, description, expire_in, password } = req.body; if (!address && !target) { throw new CustomError("Should at least update one field."); } @@ -152,7 +151,8 @@ export const edit: Handler = async (req, res) => { ...(address && { address }), ...(description && { description }), ...(target && { target }), - ...(expire_in && { expire_in }) + ...(expire_in && { expire_in }), + ...(password && { password }) } ); diff --git a/server/handlers/validators.ts b/server/handlers/validators.ts index 635401b..7b5015c 100644 --- a/server/handlers/validators.ts +++ b/server/handlers/validators.ts @@ -145,6 +145,13 @@ export const editLink = [ .withMessage("URL is not valid.") .custom(value => removeWww(URL.parse(value).host) !== env.DEFAULT_DOMAIN) .withMessage(`${env.DEFAULT_DOMAIN} URLs are not allowed.`), + body("password") + .optional({ nullable: true, checkFalsy: true }) + .custom(checkUser) + .withMessage("Only users can use this field.") + .isString() + .isLength({ min: 3, max: 64 }) + .withMessage("Password length must be between 3 and 64."), body("address") .optional({ checkFalsy: true, nullable: true }) .isString() diff --git a/server/queries/link.ts b/server/queries/link.ts index 38c9a0e..e892df8 100644 --- a/server/queries/link.ts +++ b/server/queries/link.ts @@ -180,6 +180,11 @@ export const batchRemove = async (match: Match<Link>) => { }; export const update = async (match: Partial<Link>, update: Partial<Link>) => { + if (update.password) { + const salt = await bcrypt.genSalt(12); + update.password = await bcrypt.hash(update.password, salt); + } + const links = await knex<Link>("links") .where(match) .update({ ...update, updated_at: new Date().toISOString() }, "*"); |