Skip to content

Commit

Permalink
CreateAuthor with Mongo just need to add roles now
Browse files Browse the repository at this point in the history
  • Loading branch information
J91-cloud committed Jan 10, 2025
1 parent 95550ff commit 775c382
Show file tree
Hide file tree
Showing 15 changed files with 444 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ public class Author {

@Embedded
private AuthorIdentifier authorIdentifier;
// private Username username;

private String auth0UserId; // Add this field to store Auth0 user ID
private String emailAddress;
private String firstName;
private String lastName;
private Biography biography;

@Embedded
private ArticleList articles;
// private Password password;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.calerts.computer_alertsbe.authorsubdomain.presentationlayer;

import com.calerts.computer_alertsbe.authorsubdomain.datalayer.Biography;
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class AuthorRequestDTO {
private String emailAddress;
private String password;
private String firstName;
private String lastName;
private Biography biography;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.calerts.computer_alertsbe.authorsubdomain.presentationlayer;


import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class AuthorResponseModelAuth {
private String authorId;
private String emailAddress;
private String firstName;
private String lastName;
private String auth0UserId;
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package com.calerts.computer_alertsbe.authsubdomain.businessLayer;

import com.calerts.computer_alertsbe.authorsubdomain.datalayer.*;
import com.calerts.computer_alertsbe.authorsubdomain.presentationlayer.AuthorRequestDTO;
import com.calerts.computer_alertsbe.authorsubdomain.presentationlayer.AuthorResponseModel;
import com.calerts.computer_alertsbe.authorsubdomain.presentationlayer.AuthorResponseModelAuth;
import com.calerts.computer_alertsbe.authsubdomain.presentationlayer.UserRequestDTO;
import com.calerts.computer_alertsbe.authsubdomain.presentationlayer.UserResponseModel;
import jakarta.persistence.Embedded;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;
@Service
public class UserService {
private final RestTemplate restTemplate = new RestTemplate();

private final AuthorRepository authorRepository;
private final RestTemplate restTemplate = new RestTemplate();

@Value("${auth0.domain}")
private String AUTH0_DOMAIN;
Expand All @@ -28,6 +36,10 @@ public class UserService {
@Value("${auth0.audience}")
private String AUDIENCE;

public UserService(AuthorRepository authorRepository) {
this.authorRepository = authorRepository;
}

// Retrieves the Management API token
private String getManagementApiToken() {
try {
Expand Down Expand Up @@ -94,5 +106,59 @@ public UserResponseModel createUser(UserRequestDTO request) {
throw new RuntimeException("Error communicating with Auth0: " + e.getMessage(), e);
}
}

/////////////////////////////////////////////////////////////////////////////////////////////////

public Mono<AuthorResponseModelAuth> createAuthor(AuthorRequestDTO request) {
String url = "https://" + AUTH0_DOMAIN + "/api/v2/users";
String managementApiToken = getManagementApiToken();

if (managementApiToken == null || managementApiToken.isEmpty()) {
return Mono.error(new RuntimeException("Management API token is missing or invalid"));
}

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + managementApiToken);

Map<String, Object> requestBody = new HashMap<>();
requestBody.put("email", request.getEmailAddress());
requestBody.put("password", request.getPassword());
requestBody.put("connection", "Username-Password-Authentication");

try {
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
ResponseEntity<Map> response = restTemplate.postForEntity(url, entity, Map.class);

if (response.getStatusCode() == HttpStatus.CREATED) {
Map<String, Object> responseBody = response.getBody();
String auth0UserId = (String) responseBody.get("user_id");

Author author = Author.builder()
.authorIdentifier(new AuthorIdentifier())
.emailAddress(request.getEmailAddress())
.firstName(request.getFirstName())
.lastName(request.getLastName())
// .biography(new Biography())
.articles(new ArticleList())
.auth0UserId(auth0UserId)
.build();


return authorRepository.save(author)
.map(savedAuthor -> new AuthorResponseModelAuth(
savedAuthor.getId(),
savedAuthor.getEmailAddress(),
savedAuthor.getFirstName(),
savedAuthor.getLastName(),
auth0UserId
));
} else {
return Mono.error(new RuntimeException("Failed to create user in Auth0: " + response.getBody()));
}
} catch (RestClientException e) {
return Mono.error(new RuntimeException("Error communicating with Auth0: " + e.getMessage(), e));
}
}
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.calerts.computer_alertsbe.authsubdomain.presentationlayer;

import com.calerts.computer_alertsbe.authorsubdomain.presentationlayer.AuthorRequestDTO;
import com.calerts.computer_alertsbe.authorsubdomain.presentationlayer.AuthorResponseModelAuth;
import com.calerts.computer_alertsbe.authsubdomain.businessLayer.UserService;


Expand All @@ -10,6 +12,7 @@
import org.springframework.security.core.context.SecurityContextHolder;

import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

import java.util.stream.Collectors;
@CrossOrigin(origins = {"http://localhost:3000"}, allowCredentials = "true")
Expand All @@ -31,8 +34,20 @@ public ResponseEntity<?> createUser(@RequestBody UserRequestDTO userRequest) {
.body(e.getMessage());
}
}
@PostMapping("/create/Author")
public Mono<ResponseEntity<AuthorResponseModelAuth>> createAuthor(@RequestBody AuthorRequestDTO authorRequest) {
return userService.createAuthor(authorRequest)
.map(authorResponse -> ResponseEntity
.status(HttpStatus.CREATED)
.body(authorResponse))
.onErrorResume(e -> {
System.out.println(e.getMessage());
return Mono.just(ResponseEntity
.status(HttpStatus.BAD_REQUEST).body(null)); // just return nothing or something idk
});
}

@RequestMapping(value = "/create", method = RequestMethod.OPTIONS)
@RequestMapping(value = "/create", method = RequestMethod.OPTIONS)
public ResponseEntity<?> handlePreflight() {
return ResponseEntity.ok().build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http)
.pathMatchers(HttpMethod.GET, "/api/v1/interactions/**").permitAll()
.pathMatchers(HttpMethod.POST, "/api/v1/interactions/**").permitAll()
.pathMatchers(HttpMethod.PUT, "/api/v1/articles/**").permitAll()
.pathMatchers(HttpMethod.POST, "api/create/Author").permitAll()

// Endpoints requiring authentication
.pathMatchers(HttpMethod.POST, "/api/create/**").authenticated()
Expand Down
13 changes: 12 additions & 1 deletion computer_alerts-fe/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import AdminNavBar from "./layouts/AdminDashboard/AdminNavBar";
import AdminArticleDetails from "./pages/AdminPages/AdminArticleDetails/AdminArticleDetails";
import ArtifleDrafts from "pages/AutherPages/ArticleDrafts/ArticleDrafts";
import EditArticlePage from "pages/ArticlePages/EditArticle/EditArticlePage";
import AdminAuthorsPage from "pages/AdminPages/AdminAuthors/AdminAuthorsPage";
import Footer from "assets/Footer/Footer";
import AdminCreateAuthor from "pages/AdminPages/AdminAuthors/AdminCreateAuthor/AdminCreateAuthor";

const Navbar = () => {
const location = useLocation();
Expand All @@ -38,7 +40,8 @@ const Navbar = () => {
return <AuthorNavBar />;
} else if (
location.pathname.startsWith("/adminHomePage") ||
location.pathname.startsWith("/adminReviewArticles")
location.pathname.startsWith("/adminReviewArticles") ||
location.pathname.startsWith("/adminAuthors")
) {
return <AdminNavBar />;
}
Expand Down Expand Up @@ -85,10 +88,18 @@ function App(): JSX.Element {
path={AppRoutePaths.AuthorHomePage}
element={<AdminHomePage />}
/>
<Route
path={AppRoutePaths.AdminAuthors}
element={<AdminAuthorsPage />}
/>
<Route
path={AppRoutePaths.AdminReviewArticles}
element={<AdminReviewArticles />}
/>
<Route
path={AppRoutePaths.AdminCreateAuthor}
element={<AdminCreateAuthor />}
/>
<Route path="/article/:articleId" element={<AdminArticleDetails />} />

<Route
Expand Down
51 changes: 50 additions & 1 deletion computer_alerts-fe/src/features/auth/Service/AuthService.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createAuth0Client, Auth0Client } from "@auth0/auth0-spa-js";
import axios from "axios";
import UserRequestDTO from "features/readers/models/UserRequestDTO";

import AuthorRequestDTO from "../../authors/model/AuthorRequestDTO";
export class AuthService {
URL = "http://localhost:8080/api/"; // Your backend URL

Expand Down Expand Up @@ -112,6 +112,32 @@ export class AuthService {

// Create user using the Management API token



// public Message addRole(AddRole addRole) throws UnirestException, JSONException {
// String accessToken = getAccessToken();
// String urlCompliant = addRole.getUserId().replace("|", "%7C");

// HttpResponse<String> response = Unirest.post("https://dev-7k6npylc7qks07rv.us.auth0.com/api/v2/users/" + urlCompliant + "/roles")
// .header("content-type", "application/json")
// .header("authorization", "Bearer " + accessToken)
// .header("cache-control", "no-cache")
// .body("{ \"roles\": [ \"rol_ateA49X4oBWvfywq\" ] }")
// .asString();

// log.info("response: {}", response.getBody());

// if (response.getBody() != null) {
// return Message.from("Failed to add role for user: " + addRole.getUserId());
// }

// final var text = "Role added for user: " + addRole.getUserId();

// return Message.from(text);
// }



async createUser(userRequest: UserRequestDTO): Promise<any> {
try {
// Get the Management API token before making the request
Expand Down Expand Up @@ -140,6 +166,29 @@ export class AuthService {
throw new Error(error.response?.data || "Failed to create user");
}
}

async createAuthor(authorData: AuthorRequestDTO): Promise<any> {
try {
const managementApiToken = await this.getManagementApiToken();
const response = await fetch(this.URL + 'create/Author', { // switch this
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${managementApiToken}`,
},
body: JSON.stringify(authorData)
});

if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Failed to create author');
}

return await response.json();
} catch (error) {
throw error;
}
}
}

const authTokenService = new AuthService();
Expand Down
2 changes: 2 additions & 0 deletions computer_alerts-fe/src/features/authors/api/getAllAuthors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export const getAllAuthors = async (): Promise<Author[]> => {
const response = await axiosInstance.get<Author[]>("");
return response.data;
};


Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default interface AuthorRequestDTO {
emailAddress: string;
firstName: string;
lastName: string;
password: string;
// biography: string;
connection: string;
}
8 changes: 8 additions & 0 deletions computer_alerts-fe/src/layouts/AdminDashboard/AdminNavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,15 @@ export default function AuthorNavBar(): JSX.Element {
<span></span>
</Navbar.Toggle>
<Navbar.Collapse id="basic-navbar-nav">

<Nav className="ms-auto">
<Nav.Link
as={Link}
to={AppRoutePaths.AdminAuthors}
className="nav-link"
>
AdminAuthors
</Nav.Link>
<Nav.Link
as={Link}
to={AppRoutePaths.AdminReviewArticles}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";
import { Link } from "react-router-dom";

const AdminAuthorsPage: React.FC = () =>{


return(
<div className="container">
<div className="row">
<h1>Hello</h1>
<Link to="/admin/createAuthor">
Create Author
</Link>
</div>
</div>
)
}
export default AdminAuthorsPage;
Loading

0 comments on commit 775c382

Please sign in to comment.