simple user viewing

This commit is contained in:
Stepan Usatiuk
2023-12-16 22:25:08 +01:00
parent eea123a3f0
commit 871c6950c9
10 changed files with 105 additions and 15 deletions

View File

@@ -11,12 +11,13 @@ import { Login } from "./Login";
import { Signup } from "./Signup"; import { Signup } from "./Signup";
import { Home } from "./Home"; import { Home } from "./Home";
import { loginAction, profileSelfAction, signupAction } from "./actions"; import { loginAction, profileSelfAction, signupAction } from "./actions";
import { homeLoader, profileLoader } from "./loaders"; import { homeLoader, profileLoader, userListLoader } from "./loaders";
import { isError } from "./api/dto"; import { isError } from "./api/dto";
import { Feed } from "./Feed"; import { Feed } from "./Feed";
import { Messages } from "./Messages"; import { Messages } from "./Messages";
import { Profile } from "./Profile"; import { Profile } from "./Profile";
import { getSelf } from "./api/Person"; import { UserList } from "./UserList";
import { getAllPerson } from "./api/Person";
const router = createBrowserRouter([ const router = createBrowserRouter([
{ {
@@ -38,6 +39,7 @@ const router = createBrowserRouter([
children: [ children: [
{ path: "feed", element: <Feed /> }, { path: "feed", element: <Feed /> },
{ path: "messages", element: <Messages /> }, { path: "messages", element: <Messages /> },
{ path: "users", element: <UserList />, loader: userListLoader },
{ {
path: "profile", path: "profile",
loader: profileLoader, loader: profileLoader,

View File

@@ -33,6 +33,9 @@ export function Home() {
<NavLink to={"messages"} className={activePendingClassName}> <NavLink to={"messages"} className={activePendingClassName}>
Messages Messages
</NavLink> </NavLink>
<NavLink to={"users"} className={activePendingClassName}>
Users
</NavLink>
<NavLink to={"profile"} className={activePendingClassName}> <NavLink to={"profile"} className={activePendingClassName}>
Profile Profile
</NavLink> </NavLink>

View File

@@ -1,4 +1,5 @@
import "./ProfileCard.scss"; import "./ProfileCard.scss";
import { Link } from "react-router-dom";
export function ProfileCard({ export function ProfileCard({
username, username,
@@ -9,8 +10,12 @@ export function ProfileCard({
}) { }) {
return ( return (
<div className={"profileCard"}> <div className={"profileCard"}>
<span className={"fullName"}>{fullName}</span> <Link to={`/home/profile/${username}`} className={"fullName"}>
<span className={"username"}>{username}</span> {fullName}
</Link>
<Link to={`/home/profile/${username}`} className={"username"}>
{username}
</Link>
</div> </div>
); );
} }

26
client/src/UserList.tsx Normal file
View File

@@ -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<typeof userListLoader>;
if (!loaderData || isError(loaderData)) {
return <div>Error</div>;
}
return (
<div>
{loaderData.map((u) => {
return (
<ProfileCard
username={u.username}
fullName={u.fullName}
key={u.uuid}
/>
);
})}
</div>
);
}

View File

@@ -1,5 +1,10 @@
import { fetchJSON, fetchJSONAuth } from "./utils"; import { fetchJSON, fetchJSONAuth } from "./utils";
import { PersonToResp, TPersonToResp } from "./dto"; import {
PersonToArrResp,
PersonToResp,
TPersonToArrResp,
TPersonToResp,
} from "./dto";
export async function signup( export async function signup(
username: string, username: string,
@@ -13,12 +18,24 @@ export async function signup(
}); });
} }
export async function getPersonByUuid(uuid: string): Promise<TPersonToResp> {
return fetchJSONAuth("/person/by-uuid/" + uuid, "GET", PersonToResp);
}
export async function getSelf(): Promise<TPersonToResp> { export async function getSelf(): Promise<TPersonToResp> {
return fetchJSONAuth("/person", "GET", PersonToResp); return fetchJSONAuth("/person/self", "GET", PersonToResp);
}
export async function getAllPerson(): Promise<TPersonToArrResp> {
return fetchJSONAuth("/person", "GET", PersonToArrResp);
} }
export async function getPersonByUsername( export async function getPersonByUsername(
username: string, username: string,
): Promise<TPersonToResp> { ): Promise<TPersonToResp> {
return fetchJSONAuth("/person/" + username, "GET", PersonToResp); return fetchJSONAuth(
"/person/by-username/" + username,
"GET",
PersonToResp,
);
} }

View File

@@ -33,6 +33,12 @@ export type TPersonTo = z.infer<typeof PersonTo>;
export const PersonToResp = CreateAPIResponse(PersonTo); export const PersonToResp = CreateAPIResponse(PersonTo);
export type TPersonToResp = z.infer<typeof PersonToResp>; export type TPersonToResp = z.infer<typeof PersonToResp>;
export const PersonToArr = z.array(PersonTo);
export type TPersonToArr = z.infer<typeof PersonToArr>;
export const PersonToArrResp = CreateAPIResponse(PersonToArr);
export type TPersonToArrResp = z.infer<typeof PersonToArrResp>;
export const TokenRequestTo = z.object({ export const TokenRequestTo = z.object({
username: z.string(), username: z.string(),
password: z.string(), password: z.string(),

View File

@@ -1,4 +1,4 @@
import { getPersonByUsername, getSelf } from "./api/Person"; import { getAllPerson, getPersonByUsername, getSelf } from "./api/Person";
import { deleteToken, getToken } from "./api/utils"; import { deleteToken, getToken } from "./api/utils";
import { redirect } from "react-router-dom"; import { redirect } from "react-router-dom";
import { isError } from "./api/dto"; import { isError } from "./api/dto";
@@ -24,14 +24,27 @@ export async function homeLoader() {
return await getCheckUserSelf(); return await getCheckUserSelf();
} }
export async function userListLoader() {
return await getAllPerson();
}
export async function profileLoader({ export async function profileLoader({
params, params,
}: { }: {
params: { username?: string }; 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 const user = params.username
? await getPersonByUsername(params.username) ? await getPersonByUsername(params.username)
: await getCheckUserSelf(); : self;
if (!user || user instanceof Response || isError(user)) { if (!user || user instanceof Response || isError(user)) {
return user; return user;
} }

View File

@@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.*;
import java.security.Principal; import java.security.Principal;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@RestController @RestController
@RequestMapping(value = "/person", produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(value = "/person", produces = MediaType.APPLICATION_JSON_VALUE)
@@ -35,8 +36,8 @@ public class PersonController {
return PersonMapper.makeDto(created); return PersonMapper.makeDto(created);
} }
@GetMapping(path = "/{username}") @GetMapping(path = "/by-username/{username}")
public PersonTo get(@PathVariable String username) throws UserNotFoundException { public PersonTo getByUsername(@PathVariable String username) throws UserNotFoundException {
Optional<Person> found = personService.readByUsername(username); Optional<Person> found = personService.readByUsername(username);
if (found.isEmpty()) throw new UserNotFoundException(); if (found.isEmpty()) throw new UserNotFoundException();
@@ -44,7 +45,17 @@ public class PersonController {
return PersonMapper.makeDto(found.get()); return PersonMapper.makeDto(found.get());
} }
@GetMapping @GetMapping(path = "/by-uuid/{uuid}")
public PersonTo getByUuid(@PathVariable String uuid) throws UserNotFoundException {
Optional<Person> 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 { public PersonTo getSelf(Principal principal) throws UserNotFoundException {
Optional<Person> found = personService.readById(principal.getName()); Optional<Person> found = personService.readById(principal.getName());
@@ -53,6 +64,11 @@ public class PersonController {
return PersonMapper.makeDto(found.get()); return PersonMapper.makeDto(found.get());
} }
@GetMapping
public Stream<PersonTo> getAll() throws UserNotFoundException {
return StreamSupport.stream(personService.readAll().spliterator(), false).map(PersonMapper::makeDto);
}
@GetMapping(path = "/followers") @GetMapping(path = "/followers")
public Stream<PersonTo> getFollowers(Principal principal) throws UserNotFoundException { public Stream<PersonTo> getFollowers(Principal principal) throws UserNotFoundException {
return personService.getFollowers(principal.getName()).stream().map(PersonMapper::makeDto); return personService.getFollowers(principal.getName()).stream().map(PersonMapper::makeDto);

View File

@@ -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.GET, "/post*")).permitAll() .requestMatchers(mvc.pattern(HttpMethod.GET, "/post*")).permitAll()
.requestMatchers(mvc.pattern(HttpMethod.POST, "/person")).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() .requestMatchers(mvc.pattern(HttpMethod.POST, "/token")).permitAll()
.anyRequest().hasAuthority(UserRoles.ROLE_USER.name())) .anyRequest().hasAuthority(UserRoles.ROLE_USER.name()))
.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))

View File

@@ -37,7 +37,7 @@ public class PersonControllerTest extends DemoDataDbTest {
@Test @Test
void shouldGet() { 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); HttpMethod.GET, HttpEntity.EMPTY, PersonTo.class);
Assertions.assertNotNull(response); Assertions.assertNotNull(response);
@@ -52,7 +52,7 @@ public class PersonControllerTest extends DemoDataDbTest {
@Test @Test
void shouldGetSelf() { void shouldGetSelf() {
var response = restTemplate.exchange(addr + "/person", var response = restTemplate.exchange(addr + "/person/self",
HttpMethod.GET, new HttpEntity<>(createAuthHeaders(person1Auth)), PersonTo.class); HttpMethod.GET, new HttpEntity<>(createAuthHeaders(person1Auth)), PersonTo.class);
Assertions.assertNotNull(response); Assertions.assertNotNull(response);