4 Commits

Author SHA1 Message Date
6b73952ee0 Added UserProfile endpoint (also moved stuff around) 2026-04-18 20:11:51 -04:00
22991b6a30 Annotate repos 2026-04-18 18:34:59 -04:00
13b920d911 Set initial database schema 2026-04-18 18:25:51 -04:00
134a68f5ac Flaked it up 2026-04-18 16:52:10 -04:00
19 changed files with 352 additions and 2 deletions

1
backend/.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

3
backend/.gitignore vendored
View File

@@ -35,3 +35,6 @@ out/
### VS Code ###
.vscode/
### Direnv ###
.direnv/

View File

@@ -1,12 +1,12 @@
plugins {
id 'java'
id 'org.springframework.boot' version '4.0.2'
id 'org.springframework.boot' version '4.0.5'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'net.kpuig.concord'
version = '0.0.1-SNAPSHOT'
description = 'Demo project for Spring Boot'
description = 'Concord REST Server'
java {
toolchain {
@@ -25,9 +25,14 @@ repositories {
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.springframework.boot:spring-boot-h2console'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.3'
//implementation 'org.springframework.boot:spring-boot-starter-security'
//implementation 'org.springframework.boot:spring-boot-starter-security-oauth2-resource-server'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
runtimeOnly 'com.h2database:h2:2.4.240'

61
backend/flake.lock generated Normal file
View File

@@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1776169885,
"narHash": "sha256-l/iNYDZ4bGOAFQY2q8y5OAfBBtrDAaPuRQqWaFHVRXM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4bd9165a9165d7b5e33ae57f3eecbcb28fb231c9",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

36
backend/flake.nix Normal file
View File

@@ -0,0 +1,36 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = nixpkgs.legacyPackages.${system};
in {
devShell = pkgs.mkShell {
buildInputs = with pkgs; [
jdk25
gradle
keycloak
];
shellHook = ''
mkdir -p .vscode
cat <<EOF > .vscode/settings.json
{
"java.compile.nullAnalysis.mode": "disabled",
"gradle.reuseTerminals": "all",
"java.import.gradle.java.home": "${pkgs.jdk25}/lib/openjdk",
"java.import.gradle.home": "${pkgs.gradle}/libexec/gradle",
"java.import.gradle.wrapper.enabled": false
}
EOF
echo Java Flake development environment ready!
'';
};
}
);
}

View File

@@ -0,0 +1,31 @@
package net.kpuig.concord.backend.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import net.kpuig.concord.backend.datamodels.userprofile.GetAllUserProfilesResponse;
import net.kpuig.concord.backend.datamodels.userprofile.GetUserProfileResponse;
import net.kpuig.concord.backend.services.UserProfileService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestParam;
@RestController
@RequestMapping("/user-profile")
public class UserProfileController {
@Autowired
private UserProfileService userProfileService;
@GetMapping("/")
public GetAllUserProfilesResponse getAllUserProfiles() {
return userProfileService.getAllUserProfiles();
}
@GetMapping("/{id}")
public GetUserProfileResponse getMethodName(@RequestParam String id) {
return userProfileService.getUserProfile(id);
}
}

View File

@@ -0,0 +1,26 @@
package net.kpuig.concord.backend.datamodels.channel;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import lombok.Data;
import net.kpuig.concord.backend.datamodels.server.Server;
@Data
@Entity(name = "channel")
public class Channel {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long position;
private ChannelType type;
private String name;
@ManyToOne
private Server server;
}

View File

@@ -0,0 +1,6 @@
package net.kpuig.concord.backend.datamodels.channel;
public enum ChannelType {
TEXT_CHANNEL,
VOICE_CHANNEL
}

View File

@@ -0,0 +1,28 @@
package net.kpuig.concord.backend.datamodels.message;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import lombok.Data;
import net.kpuig.concord.backend.datamodels.channel.Channel;
import net.kpuig.concord.backend.datamodels.userprofile.UserProfile;
@Data
@Entity(name = "message")
public class Message {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String content;
private Long timestamp;
@ManyToOne
private UserProfile userProfile;
@ManyToOne
private Channel channel;
}

View File

@@ -0,0 +1,21 @@
package net.kpuig.concord.backend.datamodels.server;
import java.net.URL;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;
@Data
@Entity(name = "server")
public class Server {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private URL image;
}

View File

@@ -0,0 +1,10 @@
package net.kpuig.concord.backend.datamodels.userprofile;
import java.util.List;
import lombok.Data;
@Data
public class GetAllUserProfilesResponse {
private List<GetUserProfileResponse> userProfiles;
}

View File

@@ -0,0 +1,9 @@
package net.kpuig.concord.backend.datamodels.userprofile;
import lombok.Data;
@Data
public class GetUserProfileResponse {
private Long id;
private String username;
}

View File

@@ -0,0 +1,17 @@
package net.kpuig.concord.backend.datamodels.userprofile;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;
@Data
@Entity(name = "user_profile")
public class UserProfile {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
}

View File

@@ -0,0 +1,11 @@
package net.kpuig.concord.backend.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.kpuig.concord.backend.datamodels.channel.Channel;
@Repository
public interface ChannelRepository extends JpaRepository<Channel, Long> {
}

View File

@@ -0,0 +1,11 @@
package net.kpuig.concord.backend.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.kpuig.concord.backend.datamodels.message.Message;
@Repository
public interface MessageRepository extends JpaRepository<Message, Long> {
}

View File

@@ -0,0 +1,11 @@
package net.kpuig.concord.backend.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.kpuig.concord.backend.datamodels.server.Server;
@Repository
public interface ServerRepository extends JpaRepository<Server, Long> {
}

View File

@@ -0,0 +1,13 @@
package net.kpuig.concord.backend.repositories;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.kpuig.concord.backend.datamodels.userprofile.UserProfile;
@Repository
public interface UserProfileRepository extends JpaRepository<UserProfile, Long> {
}

View File

@@ -0,0 +1,36 @@
package net.kpuig.concord.backend.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import net.kpuig.concord.backend.datamodels.userprofile.GetAllUserProfilesResponse;
import net.kpuig.concord.backend.datamodels.userprofile.GetUserProfileResponse;
import net.kpuig.concord.backend.repositories.UserProfileRepository;
@Service
public class UserProfileService {
@Autowired
private UserProfileRepository userProfileRepository;
public GetAllUserProfilesResponse getAllUserProfiles() {
GetAllUserProfilesResponse response = new GetAllUserProfilesResponse();
response.setUserProfiles(userProfileRepository.findAll().stream().map(userProfile -> {
GetUserProfileResponse userProfileResponse = new GetUserProfileResponse();
userProfileResponse.setId(userProfile.getId());
userProfileResponse.setUsername(userProfile.getUsername());
return userProfileResponse;
}).toList());
return response;
}
public GetUserProfileResponse getUserProfile(String id) {
GetUserProfileResponse response = new GetUserProfileResponse();
userProfileRepository.findById(Long.parseLong(id)).ifPresent(userProfile -> {
response.setId(userProfile.getId());
response.setUsername(userProfile.getUsername());
});
return response;
}
}

View File

@@ -1 +1,15 @@
spring.application.name=backend
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
logging.level.org.springframework=INFO
logging.level.com.example=DEBUG
server.port=8080
springdoc.api-docs.enabled=true
springdoc.api-docs.path=/v3/api-docs
springdoc.swagger-ui.enabled=true
springdoc.swagger-ui.path=/swagger