first commit
This commit is contained in:
9
backend/riotz-api/.env.example
Normal file
9
backend/riotz-api/.env.example
Normal file
@@ -0,0 +1,9 @@
|
||||
DB_URL=jdbc:postgresql://localhost:5432/riotz
|
||||
DB_USERNAME=postgres
|
||||
DB_PASSWORD=postgres
|
||||
JWT_ACCESS_SECRET=change-me-access
|
||||
JWT_REFRESH_SECRET=change-me-refresh
|
||||
JWT_ACCESS_EXPIRATION_MS=900000
|
||||
JWT_REFRESH_EXPIRATION_MS=604800000
|
||||
MEDIA_PROVIDER=s3
|
||||
MEDIA_BUCKET_NAME=riotz-media
|
||||
69
backend/riotz-api/pom.xml
Normal file
69
backend/riotz-api/pom.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.riotz</groupId>
|
||||
<artifactId>riotz-api</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>riotz-api</name>
|
||||
<description>RIOTZ backend API</description>
|
||||
|
||||
<properties>
|
||||
<java.version>21</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.riotz.api;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class RiotzApiApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(RiotzApiApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.riotz.api.admin.controller;
|
||||
|
||||
import com.riotz.api.admin.service.AdminService;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/admin")
|
||||
public class AdminController {
|
||||
|
||||
private final AdminService adminService;
|
||||
|
||||
@PatchMapping("/users/{userId}/ban")
|
||||
public ResponseEntity<Void> banUser(@PathVariable UUID userId) {
|
||||
adminService.banUser(userId);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
@DeleteMapping("/posts/{postId}")
|
||||
public ResponseEntity<Void> deletePost(@PathVariable UUID postId) {
|
||||
adminService.deletePost(postId);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.riotz.api.admin.service;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface AdminService {
|
||||
void banUser(UUID userId);
|
||||
void deletePost(UUID postId);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.riotz.api.admin.service;
|
||||
|
||||
import com.riotz.api.common.exception.ResourceNotFoundException;
|
||||
import com.riotz.api.post.repository.PostRepository;
|
||||
import com.riotz.api.user.repository.UserRepository;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AdminServiceImpl implements AdminService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final PostRepository postRepository;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void banUser(UUID userId) {
|
||||
final var user = userRepository.findById(userId)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("User not found"));
|
||||
user.setBanned(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePost(UUID postId) {
|
||||
if (!postRepository.existsById(postId)) {
|
||||
throw new ResourceNotFoundException("Post not found");
|
||||
}
|
||||
postRepository.deleteById(postId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.riotz.api.auth.controller;
|
||||
|
||||
import com.riotz.api.auth.service.AuthService;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/auth")
|
||||
public class AuthController {
|
||||
|
||||
private final AuthService authService;
|
||||
|
||||
@GetMapping("/health")
|
||||
public Map<String, String> health() {
|
||||
return Map.of("status", authService.health());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.riotz.api.auth.service;
|
||||
|
||||
public interface AuthService {
|
||||
String health();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.riotz.api.auth.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AuthServiceImpl implements AuthService {
|
||||
|
||||
@Override
|
||||
public String health() {
|
||||
return "auth-module-ready";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.riotz.api.chat.controller;
|
||||
|
||||
import com.riotz.api.chat.model.Chat;
|
||||
import com.riotz.api.chat.service.ChatService;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/chats")
|
||||
public class ChatController {
|
||||
|
||||
private final ChatService chatService;
|
||||
|
||||
@GetMapping
|
||||
public List<Chat> listChats() {
|
||||
return chatService.listChats();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.riotz.api.chat.model;
|
||||
|
||||
import com.riotz.api.common.model.BaseEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "chats")
|
||||
public class Chat extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
@Column(nullable = false, length = 120)
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
private boolean groupChat = true;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.riotz.api.chat.repository;
|
||||
|
||||
import com.riotz.api.chat.model.Chat;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ChatRepository extends JpaRepository<Chat, UUID> {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.riotz.api.chat.service;
|
||||
|
||||
import com.riotz.api.chat.model.Chat;
|
||||
import java.util.List;
|
||||
|
||||
public interface ChatService {
|
||||
List<Chat> listChats();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.riotz.api.chat.service;
|
||||
|
||||
import com.riotz.api.chat.model.Chat;
|
||||
import com.riotz.api.chat.repository.ChatRepository;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ChatServiceImpl implements ChatService {
|
||||
|
||||
private final ChatRepository chatRepository;
|
||||
|
||||
@Override
|
||||
public List<Chat> listChats() {
|
||||
return chatRepository.findAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.riotz.api.comment.controller;
|
||||
|
||||
import com.riotz.api.comment.model.Comment;
|
||||
import com.riotz.api.comment.service.CommentService;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/comments")
|
||||
public class CommentController {
|
||||
|
||||
private final CommentService commentService;
|
||||
|
||||
@GetMapping("/post/{postId}")
|
||||
public List<Comment> listPostComments(@PathVariable UUID postId) {
|
||||
return commentService.listByPost(postId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.riotz.api.comment.model;
|
||||
|
||||
import com.riotz.api.common.model.BaseEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "comments")
|
||||
public class Comment extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private UUID postId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private UUID userId;
|
||||
|
||||
@Column(nullable = false, length = 1200)
|
||||
private String content;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.riotz.api.comment.repository;
|
||||
|
||||
import com.riotz.api.comment.model.Comment;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface CommentRepository extends JpaRepository<Comment, UUID> {
|
||||
List<Comment> findByPostIdOrderByCreatedAtAsc(UUID postId);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.riotz.api.comment.service;
|
||||
|
||||
import com.riotz.api.comment.model.Comment;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface CommentService {
|
||||
List<Comment> listByPost(UUID postId);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.riotz.api.comment.service;
|
||||
|
||||
import com.riotz.api.comment.model.Comment;
|
||||
import com.riotz.api.comment.repository.CommentRepository;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CommentServiceImpl implements CommentService {
|
||||
|
||||
private final CommentRepository commentRepository;
|
||||
|
||||
@Override
|
||||
public List<Comment> listByPost(UUID postId) {
|
||||
return commentRepository.findByPostIdOrderByCreatedAtAsc(postId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.riotz.api.common.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaAuditing
|
||||
public class JpaConfig {
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.riotz.api.common.exception;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Map;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(ResourceNotFoundException.class)
|
||||
public ResponseEntity<Map<String, Object>> handleNotFound(ResourceNotFoundException ex) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of(
|
||||
"timestamp", OffsetDateTime.now(),
|
||||
"error", "NOT_FOUND",
|
||||
"message", ex.getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<Map<String, Object>> handleValidation(MethodArgumentNotValidException ex) {
|
||||
return ResponseEntity.badRequest().body(Map.of(
|
||||
"timestamp", OffsetDateTime.now(),
|
||||
"error", "VALIDATION_ERROR",
|
||||
"message", "Invalid request payload"
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.riotz.api.common.exception;
|
||||
|
||||
public class ResourceNotFoundException extends RuntimeException {
|
||||
public ResourceNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.riotz.api.common.model;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import java.time.OffsetDateTime;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@MappedSuperclass
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public abstract class BaseEntity {
|
||||
|
||||
@CreatedDate
|
||||
@Column(nullable = false, updatable = false)
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(nullable = false)
|
||||
private OffsetDateTime updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.riotz.api.message.controller;
|
||||
|
||||
import com.riotz.api.message.model.Message;
|
||||
import com.riotz.api.message.service.MessageService;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/messages")
|
||||
public class MessageController {
|
||||
|
||||
private final MessageService messageService;
|
||||
|
||||
@GetMapping("/chat/{chatId}")
|
||||
public List<Message> listByChat(@PathVariable UUID chatId) {
|
||||
return messageService.listByChat(chatId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.riotz.api.message.model;
|
||||
|
||||
import com.riotz.api.common.model.BaseEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "messages")
|
||||
public class Message extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private UUID chatId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private UUID senderId;
|
||||
|
||||
@Column(nullable = false, length = 1200)
|
||||
private String content;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.riotz.api.message.repository;
|
||||
|
||||
import com.riotz.api.message.model.Message;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface MessageRepository extends JpaRepository<Message, UUID> {
|
||||
List<Message> findByChatIdOrderByCreatedAtAsc(UUID chatId);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.riotz.api.message.service;
|
||||
|
||||
import com.riotz.api.message.model.Message;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface MessageService {
|
||||
List<Message> listByChat(UUID chatId);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.riotz.api.message.service;
|
||||
|
||||
import com.riotz.api.message.model.Message;
|
||||
import com.riotz.api.message.repository.MessageRepository;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MessageServiceImpl implements MessageService {
|
||||
|
||||
private final MessageRepository messageRepository;
|
||||
|
||||
@Override
|
||||
public List<Message> listByChat(UUID chatId) {
|
||||
return messageRepository.findByChatIdOrderByCreatedAtAsc(chatId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.riotz.api.post.controller;
|
||||
|
||||
import com.riotz.api.post.dto.PostResponse;
|
||||
import com.riotz.api.post.service.PostService;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/posts")
|
||||
public class PostController {
|
||||
|
||||
private final PostService postService;
|
||||
|
||||
@GetMapping("/feed")
|
||||
public List<PostResponse> getFeed() {
|
||||
return postService.getFeed();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.riotz.api.post.dto;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
public record PostResponse(
|
||||
UUID id,
|
||||
UUID userId,
|
||||
String caption,
|
||||
String mediaUrl,
|
||||
int likesCount,
|
||||
OffsetDateTime createdAt
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.riotz.api.post.model;
|
||||
|
||||
import com.riotz.api.common.model.BaseEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "posts")
|
||||
public class Post extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private UUID userId;
|
||||
|
||||
@Column(length = 2800)
|
||||
private String caption;
|
||||
|
||||
@Column(nullable = false, length = 1024)
|
||||
private String mediaUrl;
|
||||
|
||||
@Column(nullable = false)
|
||||
private int likesCount = 0;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.riotz.api.post.repository;
|
||||
|
||||
import com.riotz.api.post.model.Post;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface PostRepository extends JpaRepository<Post, UUID> {
|
||||
List<Post> findAllByOrderByCreatedAtDesc();
|
||||
List<Post> findByUserIdOrderByCreatedAtDesc(UUID userId);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.riotz.api.post.service;
|
||||
|
||||
import com.riotz.api.post.dto.PostResponse;
|
||||
import java.util.List;
|
||||
|
||||
public interface PostService {
|
||||
List<PostResponse> getFeed();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.riotz.api.post.service;
|
||||
|
||||
import com.riotz.api.post.dto.PostResponse;
|
||||
import com.riotz.api.post.model.Post;
|
||||
import com.riotz.api.post.repository.PostRepository;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PostServiceImpl implements PostService {
|
||||
|
||||
private final PostRepository postRepository;
|
||||
|
||||
@Override
|
||||
public List<PostResponse> getFeed() {
|
||||
return postRepository.findAllByOrderByCreatedAtDesc().stream().map(this::toResponse).toList();
|
||||
}
|
||||
|
||||
private PostResponse toResponse(Post post) {
|
||||
return new PostResponse(
|
||||
post.getId(),
|
||||
post.getUserId(),
|
||||
post.getCaption(),
|
||||
post.getMediaUrl(),
|
||||
post.getLikesCount(),
|
||||
post.getCreatedAt()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.riotz.api.profile.controller;
|
||||
|
||||
import com.riotz.api.profile.dto.ProfileResponse;
|
||||
import com.riotz.api.profile.service.ProfileService;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/profiles")
|
||||
public class ProfileController {
|
||||
|
||||
private final ProfileService profileService;
|
||||
|
||||
@GetMapping("/{userId}")
|
||||
public ProfileResponse getProfile(@PathVariable UUID userId) {
|
||||
return profileService.findByUserId(userId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.riotz.api.profile.dto;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record ProfileResponse(
|
||||
UUID userId,
|
||||
String avatarUrl,
|
||||
String bio
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.riotz.api.profile.model;
|
||||
|
||||
import com.riotz.api.common.model.BaseEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "profiles")
|
||||
public class Profile extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private UUID userId;
|
||||
|
||||
@Column(length = 1024)
|
||||
private String avatarUrl;
|
||||
|
||||
@Column(length = 280)
|
||||
private String bio;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.riotz.api.profile.repository;
|
||||
|
||||
import com.riotz.api.profile.model.Profile;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ProfileRepository extends JpaRepository<Profile, UUID> {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.riotz.api.profile.service;
|
||||
|
||||
import com.riotz.api.profile.dto.ProfileResponse;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ProfileService {
|
||||
ProfileResponse findByUserId(UUID userId);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.riotz.api.profile.service;
|
||||
|
||||
import com.riotz.api.common.exception.ResourceNotFoundException;
|
||||
import com.riotz.api.profile.dto.ProfileResponse;
|
||||
import com.riotz.api.profile.model.Profile;
|
||||
import com.riotz.api.profile.repository.ProfileRepository;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ProfileServiceImpl implements ProfileService {
|
||||
|
||||
private final ProfileRepository profileRepository;
|
||||
|
||||
@Override
|
||||
public ProfileResponse findByUserId(UUID userId) {
|
||||
return profileRepository.findById(userId)
|
||||
.map(this::toResponse)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Profile not found"));
|
||||
}
|
||||
|
||||
private ProfileResponse toResponse(Profile profile) {
|
||||
return new ProfileResponse(profile.getUserId(), profile.getAvatarUrl(), profile.getBio());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.riotz.api.security.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.cors(Customizer.withDefaults())
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.riotz.api.track.controller;
|
||||
|
||||
import com.riotz.api.track.model.Track;
|
||||
import com.riotz.api.track.service.TrackService;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/tracks")
|
||||
public class TrackController {
|
||||
|
||||
private final TrackService trackService;
|
||||
|
||||
@GetMapping("/user/{userId}")
|
||||
public List<Track> listByUser(@PathVariable UUID userId) {
|
||||
return trackService.listByUser(userId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.riotz.api.track.model;
|
||||
|
||||
import com.riotz.api.common.model.BaseEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "tracks")
|
||||
public class Track extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private UUID userId;
|
||||
|
||||
@Column(nullable = false, length = 120)
|
||||
private String title;
|
||||
|
||||
@Column(nullable = false, length = 1024)
|
||||
private String audioUrl;
|
||||
|
||||
@Column(nullable = false, length = 256)
|
||||
private String tags;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.riotz.api.track.repository;
|
||||
|
||||
import com.riotz.api.track.model.Track;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface TrackRepository extends JpaRepository<Track, UUID> {
|
||||
List<Track> findByUserIdOrderByCreatedAtDesc(UUID userId);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.riotz.api.track.service;
|
||||
|
||||
import com.riotz.api.track.model.Track;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface TrackService {
|
||||
List<Track> listByUser(UUID userId);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.riotz.api.track.service;
|
||||
|
||||
import com.riotz.api.track.model.Track;
|
||||
import com.riotz.api.track.repository.TrackRepository;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TrackServiceImpl implements TrackService {
|
||||
|
||||
private final TrackRepository trackRepository;
|
||||
|
||||
@Override
|
||||
public List<Track> listByUser(UUID userId) {
|
||||
return trackRepository.findByUserIdOrderByCreatedAtDesc(userId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.riotz.api.user.controller;
|
||||
|
||||
import com.riotz.api.user.dto.UserResponse;
|
||||
import com.riotz.api.user.service.UserService;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/v1/users")
|
||||
public class UserController {
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
@GetMapping
|
||||
public List<UserResponse> listUsers() {
|
||||
return userService.findAll();
|
||||
}
|
||||
|
||||
@GetMapping("/{userId}")
|
||||
public UserResponse getUser(@PathVariable UUID userId) {
|
||||
return userService.findById(userId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.riotz.api.user.dto;
|
||||
|
||||
import com.riotz.api.user.model.Role;
|
||||
import java.util.UUID;
|
||||
|
||||
public record UserResponse(
|
||||
UUID id,
|
||||
String email,
|
||||
String username,
|
||||
Role role,
|
||||
boolean banned
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.riotz.api.user.model;
|
||||
|
||||
public enum Role {
|
||||
USER,
|
||||
ADMIN
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.riotz.api.user.model;
|
||||
|
||||
import com.riotz.api.common.model.BaseEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
public class User extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
@Column(nullable = false, unique = true, length = 255)
|
||||
private String email;
|
||||
|
||||
@Column(nullable = false, length = 60)
|
||||
private String passwordHash;
|
||||
|
||||
@Column(nullable = false, unique = true, length = 32)
|
||||
private String username;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false, length = 16)
|
||||
private Role role = Role.USER;
|
||||
|
||||
@Column(nullable = false)
|
||||
private boolean banned = false;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.riotz.api.user.repository;
|
||||
|
||||
import com.riotz.api.user.model.User;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, UUID> {
|
||||
Optional<User> findByEmail(String email);
|
||||
Optional<User> findByUsername(String username);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.riotz.api.user.service;
|
||||
|
||||
import com.riotz.api.user.dto.UserResponse;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface UserService {
|
||||
List<UserResponse> findAll();
|
||||
UserResponse findById(UUID userId);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.riotz.api.user.service;
|
||||
|
||||
import com.riotz.api.common.exception.ResourceNotFoundException;
|
||||
import com.riotz.api.user.dto.UserResponse;
|
||||
import com.riotz.api.user.model.User;
|
||||
import com.riotz.api.user.repository.UserRepository;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserServiceImpl implements UserService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public List<UserResponse> findAll() {
|
||||
return userRepository.findAll().stream().map(this::toResponse).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserResponse findById(UUID userId) {
|
||||
return userRepository.findById(userId).map(this::toResponse)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("User not found"));
|
||||
}
|
||||
|
||||
private UserResponse toResponse(User user) {
|
||||
return new UserResponse(user.getId(), user.getEmail(), user.getUsername(), user.getRole(), user.isBanned());
|
||||
}
|
||||
}
|
||||
27
backend/riotz-api/src/main/resources/application.yml
Normal file
27
backend/riotz-api/src/main/resources/application.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
spring:
|
||||
application:
|
||||
name: riotz-api
|
||||
datasource:
|
||||
url: ${DB_URL:jdbc:postgresql://localhost:5432/riotz}
|
||||
username: ${DB_USERNAME:postgres}
|
||||
password: ${DB_PASSWORD:postgres}
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: validate
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: true
|
||||
open-in-view: false
|
||||
|
||||
server:
|
||||
port: ${SERVER_PORT:8080}
|
||||
|
||||
jwt:
|
||||
access-token-secret: ${JWT_ACCESS_SECRET:change-me-access}
|
||||
refresh-token-secret: ${JWT_REFRESH_SECRET:change-me-refresh}
|
||||
access-token-expiration-ms: ${JWT_ACCESS_EXPIRATION_MS:900000}
|
||||
refresh-token-expiration-ms: ${JWT_REFRESH_EXPIRATION_MS:604800000}
|
||||
|
||||
media:
|
||||
provider: ${MEDIA_PROVIDER:s3}
|
||||
bucket-name: ${MEDIA_BUCKET_NAME:riotz-media}
|
||||
Reference in New Issue
Block a user