mirror of
https://github.com/usatiuk/y.git
synced 2025-10-29 02:37:49 +01:00
simple user viewing
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
26
client/src/UserList.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user