Skip to content

Commit 4a84994

Browse files
authored
Merge pull request #1785 from kleros/feat/restriction-roles
feat(kleros-app): add-restrictions-check-in-upload-file
2 parents f9cb5a6 + 5c43453 commit 4a84994

File tree

7 files changed

+513
-21
lines changed

7 files changed

+513
-21
lines changed

kleros-app/src/lib/atlas/hooks/useSessionStorage.ts

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ export function useSessionStorage<T>(keyName: string, defaultValue: T) {
77

88
return value ? JSON.parse(value) : defaultValue;
99
} catch (err) {
10+
// eslint-disable-next-line no-console
11+
console.log("useSessionStorage:", { err });
12+
1013
return defaultValue;
1114
}
1215
});

kleros-app/src/lib/atlas/providers/AtlasProvider.tsx

+33-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
import { GraphQLError } from "graphql";
2626
import { isUndefined } from "../../../utils";
2727
import { useSessionStorage } from "../hooks/useSessionStorage";
28+
import { fetchRestrictions, Role } from "../utils/fetchRestrictions";
2829

2930
interface IAtlasProvider {
3031
isVerified: boolean;
@@ -44,6 +45,7 @@ interface IAtlasProvider {
4445
isError: boolean;
4546
}
4647
>;
48+
roleRestrictions: Role[] | undefined;
4749
}
4850

4951
const Context = createContext<IAtlasProvider | undefined>(undefined);
@@ -73,7 +75,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
7375
}
7476
: undefined;
7577
return new GraphQLClient(`${config.uri}/graphql`, { headers });
76-
}, [authToken]);
78+
}, [authToken, config.uri]);
7779

7880
/**
7981
* @description verifies user authorisation
@@ -142,6 +144,22 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
142144
queryClient
143145
);
144146

147+
const { data: roleRestrictions } = useQuery(
148+
{
149+
queryKey: [`RoleRestrictions`],
150+
enabled: Boolean(config.product),
151+
staleTime: Infinity,
152+
queryFn: async () => {
153+
try {
154+
return await fetchRestrictions(atlasGqlClient, config.product);
155+
} catch {
156+
return undefined;
157+
}
158+
},
159+
},
160+
queryClient
161+
);
162+
145163
useEffect(() => {
146164
if (!isVerified) return;
147165
refetchUser();
@@ -255,6 +273,17 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
255273
async (file: File, role: Roles) => {
256274
try {
257275
if (!address || !isVerified || !config.uri || !authToken) return null;
276+
277+
if (roleRestrictions) {
278+
const restrictions = roleRestrictions.find((supportedRoles) => Roles[supportedRoles.name] === role);
279+
280+
if (!restrictions) throw new Error("Unsupported role.");
281+
if (!restrictions.restriction.allowedMimeTypes.includes(file.type)) throw new Error("Unsupported file type.");
282+
if (file.size > restrictions.restriction.maxSize)
283+
throw new Error(
284+
`File too big. Max allowed size : ${(restrictions.restriction.maxSize / (1024 * 1024)).toFixed(2)} mb.`
285+
);
286+
}
258287
setIsUploadingFile(true);
259288

260289
const hash = await fetchWithAuthErrorHandling(() =>
@@ -267,7 +296,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
267296
setIsUploadingFile(false);
268297
}
269298
},
270-
[address, isVerified, setIsUploadingFile, authToken, config.uri, config.product]
299+
[address, isVerified, setIsUploadingFile, authToken, config.uri, config.product, roleRestrictions]
271300
);
272301

273302
/**
@@ -309,6 +338,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
309338
isUploadingFile,
310339
uploadFile,
311340
confirmEmail,
341+
roleRestrictions,
312342
}),
313343
[
314344
isVerified,
@@ -324,6 +354,7 @@ export const AtlasProvider: React.FC<{ config: AtlasConfig; children?: React.Rea
324354
isUploadingFile,
325355
uploadFile,
326356
confirmEmail,
357+
roleRestrictions,
327358
]
328359
)}
329360
>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { gql, type GraphQLClient } from "graphql-request";
2+
import { Products } from ".";
3+
4+
export type Role = {
5+
name: string;
6+
restriction: {
7+
maxSize: number;
8+
allowedMimeTypes: string[];
9+
};
10+
};
11+
12+
type FetchRolesResponse = {
13+
roles: Role[];
14+
};
15+
16+
const query = gql`
17+
query Roles($product: Products!) {
18+
roles(product: $product) {
19+
name
20+
restriction {
21+
maxSize
22+
allowedMimeTypes
23+
}
24+
}
25+
}
26+
`;
27+
28+
export async function fetchRestrictions(client: GraphQLClient, product: Products): Promise<Role[]> {
29+
return client
30+
.request<FetchRolesResponse>(query, { product })
31+
.then((response) => response.roles)
32+
.catch((errors) => {
33+
// eslint-disable-next-line no-console
34+
console.log("Error fetching roles :", { errors });
35+
const errorMessage = Array.isArray(errors?.response?.errors)
36+
? errors.response.errors[0]?.message
37+
: "Error fetching roles";
38+
throw Error(errorMessage);
39+
});
40+
}

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
"web-devtools",
2626
"eslint-config",
2727
"prettier-config",
28-
"tsconfig"
28+
"tsconfig",
29+
"kleros-app"
2930
],
3031
"packageManager": "[email protected]",
3132
"volta": {

web/src/pages/Home/CourtOverview/Header.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import React from "react";
22
import styled from "styled-components";
33

4-
import { responsiveSize } from "styles/responsiveSize";
5-
64
import { Button } from "@kleros/ui-components-library";
75

86
import Bookmark from "svgs/icons/bookmark.svg";
97

8+
import { responsiveSize } from "styles/responsiveSize";
9+
1010
import { InternalLink } from "components/InternalLink";
1111

1212
const StyledHeader = styled.div`

0 commit comments

Comments
 (0)