From 871c6950c9131f5a59ab28be9f79b8f92640892b Mon Sep 17 00:00:00 2001 From: Stepan Usatiuk Date: Sat, 16 Dec 2023 22:25:08 +0100 Subject: [PATCH] simple user viewing --- client/src/App.tsx | 6 +++-- client/src/Home.tsx | 3 +++ client/src/ProfileCard.tsx | 9 +++++-- client/src/UserList.tsx | 26 +++++++++++++++++++ client/src/api/Person.ts | 23 +++++++++++++--- client/src/api/dto.ts | 6 +++++ client/src/loaders.ts | 17 ++++++++++-- .../y/server/controller/PersonController.java | 22 +++++++++++++--- .../y/server/security/WebSecurityConfig.java | 4 ++- .../controller/PersonControllerTest.java | 4 +-- 10 files changed, 105 insertions(+), 15 deletions(-) create mode 100644 client/src/UserList.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index 74f1ca6..dd4e6fe 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -11,12 +11,13 @@ import { Login } from "./Login"; import { Signup } from "./Signup"; import { Home } from "./Home"; import { loginAction, profileSelfAction, signupAction } from "./actions"; -import { homeLoader, profileLoader } from "./loaders"; +import { homeLoader, profileLoader, userListLoader } from "./loaders"; import { isError } from "./api/dto"; import { Feed } from "./Feed"; import { Messages } from "./Messages"; import { Profile } from "./Profile"; -import { getSelf } from "./api/Person"; +import { UserList } from "./UserList"; +import { getAllPerson } from "./api/Person"; const router = createBrowserRouter([ { @@ -38,6 +39,7 @@ const router = createBrowserRouter([ children: [ { path: "feed", element: }, { path: "messages", element: }, + { path: "users", element: , loader: userListLoader }, { path: "profile", loader: profileLoader, diff --git a/client/src/Home.tsx b/client/src/Home.tsx index 538e600..a579106 100644 --- a/client/src/Home.tsx +++ b/client/src/Home.tsx @@ -33,6 +33,9 @@ export function Home() { Messages + + Users + Profile diff --git a/client/src/ProfileCard.tsx b/client/src/ProfileCard.tsx index cd96a22..614813a 100644 --- a/client/src/ProfileCard.tsx +++ b/client/src/ProfileCard.tsx @@ -1,4 +1,5 @@ import "./ProfileCard.scss"; +import { Link } from "react-router-dom"; export function ProfileCard({ username, @@ -9,8 +10,12 @@ export function ProfileCard({ }) { return (
- {fullName} - {username} + + {fullName} + + + {username} +
); } diff --git a/client/src/UserList.tsx b/client/src/UserList.tsx new file mode 100644 index 0000000..6cf445d --- /dev/null +++ b/client/src/UserList.tsx @@ -0,0 +1,26 @@ +import { useLoaderData } from "react-router-dom"; +import { LoaderToType, userListLoader } from "./loaders"; +import { isError } from "./api/dto"; +import { ProfileCard } from "./ProfileCard"; + +export function UserList() { + const loaderData = useLoaderData() as LoaderToType; + + if (!loaderData || isError(loaderData)) { + return
Error
; + } + + return ( +
+ {loaderData.map((u) => { + return ( + + ); + })} +
+ ); +} diff --git a/client/src/api/Person.ts b/client/src/api/Person.ts index 0cf5b72..9b19ba9 100644 --- a/client/src/api/Person.ts +++ b/client/src/api/Person.ts @@ -1,5 +1,10 @@ import { fetchJSON, fetchJSONAuth } from "./utils"; -import { PersonToResp, TPersonToResp } from "./dto"; +import { + PersonToArrResp, + PersonToResp, + TPersonToArrResp, + TPersonToResp, +} from "./dto"; export async function signup( username: string, @@ -13,12 +18,24 @@ export async function signup( }); } +export async function getPersonByUuid(uuid: string): Promise { + return fetchJSONAuth("/person/by-uuid/" + uuid, "GET", PersonToResp); +} + export async function getSelf(): Promise { - return fetchJSONAuth("/person", "GET", PersonToResp); + return fetchJSONAuth("/person/self", "GET", PersonToResp); +} + +export async function getAllPerson(): Promise { + return fetchJSONAuth("/person", "GET", PersonToArrResp); } export async function getPersonByUsername( username: string, ): Promise { - return fetchJSONAuth("/person/" + username, "GET", PersonToResp); + return fetchJSONAuth( + "/person/by-username/" + username, + "GET", + PersonToResp, + ); } diff --git a/client/src/api/dto.ts b/client/src/api/dto.ts index baca452..2d84724 100644 --- a/client/src/api/dto.ts +++ b/client/src/api/dto.ts @@ -33,6 +33,12 @@ export type TPersonTo = z.infer; export const PersonToResp = CreateAPIResponse(PersonTo); export type TPersonToResp = z.infer; +export const PersonToArr = z.array(PersonTo); +export type TPersonToArr = z.infer; + +export const PersonToArrResp = CreateAPIResponse(PersonToArr); +export type TPersonToArrResp = z.infer; + export const TokenRequestTo = z.object({ username: z.string(), password: z.string(), diff --git a/client/src/loaders.ts b/client/src/loaders.ts index 7837ef5..2f5f14a 100644 --- a/client/src/loaders.ts +++ b/client/src/loaders.ts @@ -1,4 +1,4 @@ -import { getPersonByUsername, getSelf } from "./api/Person"; +import { getAllPerson, getPersonByUsername, getSelf } from "./api/Person"; import { deleteToken, getToken } from "./api/utils"; import { redirect } from "react-router-dom"; import { isError } from "./api/dto"; @@ -24,14 +24,27 @@ export async function homeLoader() { return await getCheckUserSelf(); } +export async function userListLoader() { + return await getAllPerson(); +} + export async function profileLoader({ params, }: { params: { username?: string }; }) { + const self = await getCheckUserSelf(); + if (!self || self instanceof Response || isError(self)) { + return self; + } + + if (self.username == params.username) { + return redirect("/home/profile"); + } + const user = params.username ? await getPersonByUsername(params.username) - : await getCheckUserSelf(); + : self; if (!user || user instanceof Response || isError(user)) { return user; } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/controller/PersonController.java b/server/src/main/java/com/usatiuk/tjv/y/server/controller/PersonController.java index 98f3c34..c4410b8 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/controller/PersonController.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/controller/PersonController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.*; import java.security.Principal; import java.util.Optional; import java.util.stream.Stream; +import java.util.stream.StreamSupport; @RestController @RequestMapping(value = "/person", produces = MediaType.APPLICATION_JSON_VALUE) @@ -35,8 +36,8 @@ public class PersonController { return PersonMapper.makeDto(created); } - @GetMapping(path = "/{username}") - public PersonTo get(@PathVariable String username) throws UserNotFoundException { + @GetMapping(path = "/by-username/{username}") + public PersonTo getByUsername(@PathVariable String username) throws UserNotFoundException { Optional found = personService.readByUsername(username); if (found.isEmpty()) throw new UserNotFoundException(); @@ -44,7 +45,17 @@ public class PersonController { return PersonMapper.makeDto(found.get()); } - @GetMapping + @GetMapping(path = "/by-uuid/{uuid}") + public PersonTo getByUuid(@PathVariable String uuid) throws UserNotFoundException { + Optional found = personService.readById(uuid); + + if (found.isEmpty()) throw new UserNotFoundException(); + + return PersonMapper.makeDto(found.get()); + } + + + @GetMapping(path = "/self") public PersonTo getSelf(Principal principal) throws UserNotFoundException { Optional found = personService.readById(principal.getName()); @@ -53,6 +64,11 @@ public class PersonController { return PersonMapper.makeDto(found.get()); } + @GetMapping + public Stream getAll() throws UserNotFoundException { + return StreamSupport.stream(personService.readAll().spliterator(), false).map(PersonMapper::makeDto); + } + @GetMapping(path = "/followers") public Stream getFollowers(Principal principal) throws UserNotFoundException { return personService.getFollowers(principal.getName()).stream().map(PersonMapper::makeDto); diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/security/WebSecurityConfig.java b/server/src/main/java/com/usatiuk/tjv/y/server/security/WebSecurityConfig.java index 24c87df..a43df67 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/security/WebSecurityConfig.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/security/WebSecurityConfig.java @@ -63,7 +63,9 @@ public class WebSecurityConfig { .requestMatchers(mvc.pattern(HttpMethod.GET, "/post/*")).permitAll() .requestMatchers(mvc.pattern(HttpMethod.GET, "/post*")).permitAll() .requestMatchers(mvc.pattern(HttpMethod.POST, "/person")).permitAll() - .requestMatchers(mvc.pattern(HttpMethod.GET, "/person/*")).permitAll() + .requestMatchers(mvc.pattern(HttpMethod.GET, "/person")).permitAll() + .requestMatchers(mvc.pattern(HttpMethod.GET, "/person/by-username/*")).permitAll() + .requestMatchers(mvc.pattern(HttpMethod.GET, "/person/by-uuid/*")).permitAll() .requestMatchers(mvc.pattern(HttpMethod.POST, "/token")).permitAll() .anyRequest().hasAuthority(UserRoles.ROLE_USER.name())) .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) diff --git a/server/src/test/java/com/usatiuk/tjv/y/server/controller/PersonControllerTest.java b/server/src/test/java/com/usatiuk/tjv/y/server/controller/PersonControllerTest.java index 41c10ec..2dd6595 100644 --- a/server/src/test/java/com/usatiuk/tjv/y/server/controller/PersonControllerTest.java +++ b/server/src/test/java/com/usatiuk/tjv/y/server/controller/PersonControllerTest.java @@ -37,7 +37,7 @@ public class PersonControllerTest extends DemoDataDbTest { @Test void shouldGet() { - var response = restTemplate.exchange(addr + "/person/" + person1.getUsername(), + var response = restTemplate.exchange(addr + "/person/by-username/" + person1.getUsername(), HttpMethod.GET, HttpEntity.EMPTY, PersonTo.class); Assertions.assertNotNull(response); @@ -52,7 +52,7 @@ public class PersonControllerTest extends DemoDataDbTest { @Test void shouldGetSelf() { - var response = restTemplate.exchange(addr + "/person", + var response = restTemplate.exchange(addr + "/person/self", HttpMethod.GET, new HttpEntity<>(createAuthHeaders(person1Auth)), PersonTo.class); Assertions.assertNotNull(response);