Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
config.ts
dist
node_modules
.env
# Maven build output
target/

# IDE files
.idea/
*.iml
.classpath
.project
.settings/
*.class

# Environment / secrets
.env

# macOS
.DS_Store
1,587 changes: 0 additions & 1,587 deletions backend/package-lock.json

This file was deleted.

32 changes: 0 additions & 32 deletions backend/package.json

This file was deleted.

90 changes: 90 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.4.3</version>
<relativePath/>
</parent>

<groupId>com.secondbrain</groupId>
<artifactId>second-brain</artifactId>
<version>1.0.0</version>
<name>second-brain</name>
<description>Second Brain API - Spring Boot</description>

<properties>
<java.version>17</java.version>
<jjwt.version>0.12.6</jjwt.version>
</properties>

<dependencies>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Spring Data MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- Spring Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<!-- JJWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>

<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-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>
55 changes: 0 additions & 55 deletions backend/src/index.ts

This file was deleted.

12 changes: 12 additions & 0 deletions backend/src/main/java/com/secondbrain/SecondBrainApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.secondbrain;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SecondBrainApplication {

public static void main(String[] args) {
SpringApplication.run(SecondBrainApplication.class, args);
}
}
68 changes: 68 additions & 0 deletions backend/src/main/java/com/secondbrain/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.secondbrain.config;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import com.secondbrain.security.JwtAuthFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Autowired
private JwtAuthFilter jwtAuthFilter;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// CSRF is disabled because this is a stateless REST API using JWT in the
// Authorization header. Browsers cannot be tricked into sending that header
// cross-site, so CSRF protection is not necessary here.
.csrf(csrf -> csrf.disable())
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.GET, "/").permitAll()
.requestMatchers(HttpMethod.POST, "/api/v1/user/signup").permitAll()
.requestMatchers(HttpMethod.POST, "/api/v1/user/signin").permitAll()
.requestMatchers(HttpMethod.GET, "/api/v1/brain/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

return http.build();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOriginPatterns(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowCredentials(false);

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.secondbrain.controller;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.secondbrain.dto.ContentRequest;
import com.secondbrain.model.Content;
import com.secondbrain.repository.ContentRepository;

import jakarta.validation.Valid;

@RestController
@RequestMapping("/api/v1/content")
public class ContentController {

@Autowired
private ContentRepository contentRepository;

@PostMapping
public ResponseEntity<?> create(@Valid @RequestBody ContentRequest request, Authentication auth) {
String userId = (String) auth.getPrincipal();

Content content = new Content();
content.setTitle(request.getTitle());
content.setLink(request.getLink());
content.setType(request.getType());
content.setUserId(userId);
content.setTags(Collections.emptyList());

contentRepository.save(content);
return ResponseEntity.ok(Map.of("message", "Content added"));
}

@GetMapping
public ResponseEntity<?> list(Authentication auth) {
String userId = (String) auth.getPrincipal();
List<Content> content = contentRepository.findByUserId(userId);
return ResponseEntity.ok(Map.of("content", content));
}

@DeleteMapping
public ResponseEntity<?> delete(@RequestBody Map<String, String> body, Authentication auth) {
String userId = (String) auth.getPrincipal();
String contentId = body.get("contenetId");
if (contentId != null) {
contentRepository.deleteByIdAndUserId(contentId, userId);
}
return ResponseEntity.ok(Map.of("message", "Deleted"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.secondbrain.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RootController {

@GetMapping("/")
public String root() {
return "Hello";
}
}
Loading