Compare commits
60 commits
8b2422dd1b
...
a398641172
Author | SHA1 | Date | |
---|---|---|---|
a398641172 | |||
4ce0f70d5d | |||
568e175208 | |||
e6b7f10b87 | |||
7d4ff3ce64 | |||
1060d4d577 | |||
24adb8d0ce | |||
ceb2fe27a7 | |||
bc4a5240d7 | |||
9b6409914a | |||
391f3969c6 | |||
abbb02729a | |||
0769040fc0 | |||
5d34208625 | |||
e24f80cea5 | |||
40d33a45e6 | |||
ac43032aab | |||
12e807c5ed | |||
44c6a3b1a7 | |||
cf42778103 | |||
3c1a049dd7 | |||
5509126896 | |||
2b3d812c00 | |||
c1e2f4c4f3 | |||
aaffdda371 | |||
ed6ff54537 | |||
255a4ede3e | |||
806aee663d | |||
816eddd039 | |||
acfec04173 | |||
86de126b41 | |||
bfa5372ce4 | |||
a7388de9f5 | |||
b82355ea1a | |||
48cc667d26 | |||
6cde6438d2 | |||
c096ec17c1 | |||
656e202abd | |||
80b92dd1ea | |||
cb0633b9a2 | |||
6d837c514a | |||
3c8e2ed5e0 | |||
63b18c3f9f | |||
170300d67f | |||
56fb3bfe36 | |||
b0dabe0c61 | |||
9bf662fc78 | |||
e5194fed4f | |||
6d490ae25f | |||
a8fa525a30 | |||
0af571adf6 | |||
6f8b682f0a | |||
8323dd48ba | |||
dca11b2347 | |||
a0204e4da4 | |||
9a2861fc3f | |||
6c267b232c | |||
d5a6da0647 | |||
9914171dcb | |||
b96a544452 |
68 changed files with 6084 additions and 553 deletions
|
@ -1,3 +1,13 @@
|
||||||
*
|
*
|
||||||
!src/
|
!src/
|
||||||
!pom.xml
|
!pom.xml
|
||||||
|
!ui/package*.json
|
||||||
|
!ui/postcss.config.js
|
||||||
|
!ui/tailwind.config.js
|
||||||
|
!ui/env.d..ts
|
||||||
|
!ui/vite.config.ts
|
||||||
|
!ui/tsconfig.json
|
||||||
|
!ui/tsconfig.node.json
|
||||||
|
!ui/index.html
|
||||||
|
!ui/public/
|
||||||
|
!ui/src/
|
14
Dockerfile
14
Dockerfile
|
@ -1,4 +1,4 @@
|
||||||
# Stage 1: Build the application
|
# Stage 1: Build java application
|
||||||
FROM docker.io/maven:3.9-eclipse-temurin-19 AS maven
|
FROM docker.io/maven:3.9-eclipse-temurin-19 AS maven
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY pom.xml .
|
COPY pom.xml .
|
||||||
|
@ -7,9 +7,19 @@ RUN mvn package
|
||||||
COPY src/ /app/src/
|
COPY src/ /app/src/
|
||||||
RUN mvn package
|
RUN mvn package
|
||||||
|
|
||||||
# Stage 2: Create the jlink app
|
# Stage 2: Build vuejs application
|
||||||
|
FROM docker.io/node:18-slim AS vuejs
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./ui/package* .
|
||||||
|
RUN npm ci
|
||||||
|
COPY ./ui .
|
||||||
|
RUN npm run build-only
|
||||||
|
|
||||||
|
# Stage 3: Create the jlink app
|
||||||
FROM docker.io/eclipse-temurin:19-jdk
|
FROM docker.io/eclipse-temurin:19-jdk
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=maven /app/target/dchat-*-fat.jar /app/dchat.jar
|
COPY --from=maven /app/target/dchat-*-fat.jar /app/dchat.jar
|
||||||
|
COPY --from=vuejs /app/dist /app/ui/dist
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
CMD ["java", "--enable-preview", "-jar", "/app/dchat.jar"]
|
CMD ["java", "--enable-preview", "-jar", "/app/dchat.jar"]
|
||||||
|
|
|
@ -22,12 +22,6 @@ and navigate into it.
|
||||||
Change the environment variable inside the `docker-compose.yml`.
|
Change the environment variable inside the `docker-compose.yml`.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
podman-compose pull
|
|
||||||
podman-compose start db
|
|
||||||
podman cp schema.sql dchat_db_1:/schema.sql
|
|
||||||
podman exec -it dchat_db_1 /bin/bash
|
|
||||||
psql --user dchat dchat < schema.sql
|
|
||||||
exit
|
|
||||||
podman-compose up -d
|
podman-compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,6 @@ services:
|
||||||
- POSTGRES_PASSWORD=<postgres-password>
|
- POSTGRES_PASSWORD=<postgres-password>
|
||||||
- POSTGRES_URL=jdbc:postgresql://db:5432/dchat
|
- POSTGRES_URL=jdbc:postgresql://db:5432/dchat
|
||||||
- API_PORT=8080
|
- API_PORT=8080
|
||||||
- API_USERNAME=<api-username>
|
|
||||||
- API_PASSWORD=<api-password>
|
|
||||||
db:
|
db:
|
||||||
image: docker.io/postgres:15-alpine
|
image: docker.io/postgres:15-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -40,7 +40,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.javalin</groupId>
|
<groupId>io.javalin</groupId>
|
||||||
<artifactId>javalin</artifactId>
|
<artifactId>javalin</artifactId>
|
||||||
<version>5.4.2</version>
|
<version>5.5.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- logging -->
|
<!-- logging -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
36
src/main/java/de/hhhammer/dchat/DBMigrator.java
Normal file
36
src/main/java/de/hhhammer/dchat/DBMigrator.java
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package de.hhhammer.dchat;
|
||||||
|
|
||||||
|
import de.hhhammer.dchat.migration.DBMigrationException;
|
||||||
|
import de.hhhammer.dchat.migration.MigrationExecutor;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class DBMigrator implements Runnable {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DBMigrator.class);
|
||||||
|
private final MigrationExecutor migrationExecutor;
|
||||||
|
private final String resourcePath;
|
||||||
|
|
||||||
|
public DBMigrator(MigrationExecutor migrationExecutor, String resourcePath) {
|
||||||
|
this.migrationExecutor = migrationExecutor;
|
||||||
|
this.resourcePath = resourcePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
logger.info("Starting db migration");
|
||||||
|
ClassLoader classLoader = getClass().getClassLoader();
|
||||||
|
try (InputStream inputStream = classLoader.getResourceAsStream(this.resourcePath)) {
|
||||||
|
if (inputStream == null) {
|
||||||
|
logger.error("Migration file not found: " + resourcePath);
|
||||||
|
throw new RuntimeException("Migration file not found");
|
||||||
|
}
|
||||||
|
migrationExecutor.migrate(inputStream);
|
||||||
|
} catch (IOException | DBMigrationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
logger.info("Finished migration");
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,7 +56,7 @@ public class DiscordBot implements Runnable {
|
||||||
if (server.isEmpty()) {
|
if (server.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var tokens = this.serverDBService.tokensOfLast30Days(server.get().getId());
|
var tokens = this.serverDBService.tokensOfLast30Days(String.valueOf(server.get().getId()));
|
||||||
interactionOriginalResponseUpdater.setContent("" + tokens).update();
|
interactionOriginalResponseUpdater.setContent("" + tokens).update();
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -2,22 +2,26 @@ package de.hhhammer.dchat;
|
||||||
|
|
||||||
import de.hhhammer.dchat.db.ServerDBService;
|
import de.hhhammer.dchat.db.ServerDBService;
|
||||||
import de.hhhammer.dchat.db.UserDBService;
|
import de.hhhammer.dchat.db.UserDBService;
|
||||||
|
import de.hhhammer.dchat.migration.MigrationExecutor;
|
||||||
import de.hhhammer.dchat.openai.ChatGPTService;
|
import de.hhhammer.dchat.openai.ChatGPTService;
|
||||||
import de.hhhammer.dchat.web.JavalinConfig;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(Main.class);
|
private static final Logger logger = LoggerFactory.getLogger(Main.class);
|
||||||
|
private static final String DB_MIGRATION_PATH = "db/schema.sql";
|
||||||
private final DiscordBot discordBot;
|
private final DiscordBot discordBot;
|
||||||
private final WebAPI webAPI;
|
private final WebAPI webAPI;
|
||||||
|
private final DBMigrator dbMigrator;
|
||||||
|
|
||||||
public Main(DiscordBot discordBot, WebAPI webAPI) {
|
public Main(DiscordBot discordBot, WebAPI webAPI, DBMigrator dbMigrator) {
|
||||||
this.discordBot = discordBot;
|
this.discordBot = discordBot;
|
||||||
this.webAPI = webAPI;
|
this.webAPI = webAPI;
|
||||||
|
this.dbMigrator = dbMigrator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,13 +43,8 @@ public class Main {
|
||||||
logger.error("Missing environment variables: POSTGRES_USER and/or POSTGRES_PASSWORD and/or POSTGRES_URL");
|
logger.error("Missing environment variables: POSTGRES_USER and/or POSTGRES_PASSWORD and/or POSTGRES_URL");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
String apiUsername = System.getenv("API_USERNAME");
|
|
||||||
String apiPassword = System.getenv("API_PASSWORD");
|
String apiPortStr = System.getenv("API_PORT") != null ? System.getenv("API_PORT") : "8080";
|
||||||
if (apiUsername == null || apiPassword == null) {
|
|
||||||
logger.error("Missing environment variables: API_USERNAME and/or API_PASSWORD");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
String apiPortStr = System.getenv("PAI_PORT") != null ? System.getenv("API_PORT") : "8080";
|
|
||||||
int apiPort = Integer.parseInt(apiPortStr);
|
int apiPort = Integer.parseInt(apiPortStr);
|
||||||
|
|
||||||
var chatGPTService = new ChatGPTService(openaiApiKey, HttpClient.newHttpClient());
|
var chatGPTService = new ChatGPTService(openaiApiKey, HttpClient.newHttpClient());
|
||||||
|
@ -53,16 +52,20 @@ public class Main {
|
||||||
var userDBService = new UserDBService(postgresUrl, postgresUser, postgresPassword);
|
var userDBService = new UserDBService(postgresUrl, postgresUser, postgresPassword);
|
||||||
|
|
||||||
var discordBot = new DiscordBot(serverDBService, userDBService, chatGPTService, discordApiKey);
|
var discordBot = new DiscordBot(serverDBService, userDBService, chatGPTService, discordApiKey);
|
||||||
var javalinConfig = new JavalinConfig(apiPort, apiUsername, apiPassword);
|
var webAPI = new WebAPI(serverDBService, userDBService, apiPort);
|
||||||
var webAPI = new WebAPI(serverDBService, userDBService, javalinConfig);
|
var dbMigrator = new DBMigrator(new MigrationExecutor(postgresUrl, postgresUser, postgresPassword), DB_MIGRATION_PATH);
|
||||||
new Main(discordBot, webAPI).run();
|
new Main(discordBot, webAPI, dbMigrator).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.info("Starting services...");
|
logger.info("Starting services...");
|
||||||
try (var executor = Executors.newFixedThreadPool(2)) {
|
try (var executor = Executors.newFixedThreadPool(2)) {
|
||||||
|
var migrationResult = executor.submit(dbMigrator);
|
||||||
|
migrationResult.get();
|
||||||
executor.submit(discordBot);
|
executor.submit(discordBot);
|
||||||
executor.submit(webAPI);
|
executor.submit(webAPI);
|
||||||
|
} catch (ExecutionException | InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,13 +2,11 @@ package de.hhhammer.dchat;
|
||||||
|
|
||||||
import de.hhhammer.dchat.db.ServerDBService;
|
import de.hhhammer.dchat.db.ServerDBService;
|
||||||
import de.hhhammer.dchat.db.UserDBService;
|
import de.hhhammer.dchat.db.UserDBService;
|
||||||
import de.hhhammer.dchat.web.JavalinConfig;
|
|
||||||
import de.hhhammer.dchat.web.server.AllowedCrudHandler;
|
|
||||||
import de.hhhammer.dchat.web.server.ConfigCrudHandler;
|
import de.hhhammer.dchat.web.server.ConfigCrudHandler;
|
||||||
import de.hhhammer.dchat.web.user.AllowedUserCrudHandler;
|
|
||||||
import de.hhhammer.dchat.web.user.ConfigUserCrudHandler;
|
import de.hhhammer.dchat.web.user.ConfigUserCrudHandler;
|
||||||
import io.javalin.Javalin;
|
import io.javalin.Javalin;
|
||||||
import io.javalin.http.HttpStatus;
|
import io.javalin.http.HttpStatus;
|
||||||
|
import io.javalin.http.staticfiles.Location;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -19,12 +17,12 @@ public class WebAPI implements Runnable {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(WebAPI.class);
|
private static final Logger logger = LoggerFactory.getLogger(WebAPI.class);
|
||||||
private final ServerDBService serverDBService;
|
private final ServerDBService serverDBService;
|
||||||
private final UserDBService userDBService;
|
private final UserDBService userDBService;
|
||||||
private final JavalinConfig javalinConfig;
|
private final int port;
|
||||||
|
|
||||||
public WebAPI(ServerDBService serverDBService, UserDBService userDBService, JavalinConfig javalinConfig) {
|
public WebAPI(ServerDBService serverDBService, UserDBService userDBService, int port) {
|
||||||
this.serverDBService = serverDBService;
|
this.serverDBService = serverDBService;
|
||||||
this.userDBService = userDBService;
|
this.userDBService = userDBService;
|
||||||
this.javalinConfig = javalinConfig;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -34,17 +32,10 @@ public class WebAPI implements Runnable {
|
||||||
config.plugins.enableDevLogging();
|
config.plugins.enableDevLogging();
|
||||||
config.http.prefer405over404 = true; // return 405 instead of 404 if path is mapped to different HTTP method
|
config.http.prefer405over404 = true; // return 405 instead of 404 if path is mapped to different HTTP method
|
||||||
config.http.defaultContentType = "application/json";
|
config.http.defaultContentType = "application/json";
|
||||||
config.accessManager((handler, context, set) -> {
|
config.staticFiles.add(staticFileConfig -> {
|
||||||
var creds = context.basicAuthCredentials();
|
staticFileConfig.hostedPath = "/";
|
||||||
if (creds == null) {
|
staticFileConfig.location = Location.EXTERNAL;
|
||||||
context.status(HttpStatus.UNAUTHORIZED);
|
staticFileConfig.directory = "./ui/dist/";
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!javalinConfig.username().equals(creds.getUsername()) || !javalinConfig.password().equals(creds.getPassword())) {
|
|
||||||
context.status(HttpStatus.UNAUTHORIZED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handler.handle(context);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
|
@ -55,22 +46,28 @@ public class WebAPI implements Runnable {
|
||||||
event.serverStopping(() -> logger.info("Stopping web service"));
|
event.serverStopping(() -> logger.info("Stopping web service"));
|
||||||
event.serverStopped(() -> logger.info("Stopped web service"));
|
event.serverStopped(() -> logger.info("Stopped web service"));
|
||||||
});
|
});
|
||||||
|
app.before(ctx -> {
|
||||||
app.get("/", ctx -> ctx.result("""
|
ctx.header("Access-Control-Allow-Origin", "*");
|
||||||
{ "message": "Hello World"}
|
ctx.header("Access-Control-Allow-Methods", "*");
|
||||||
"""));
|
});
|
||||||
|
app.after(ctx -> {
|
||||||
|
if (!ctx.path().startsWith("/api") && (ctx.status().equals(HttpStatus.NOT_FOUND) || ctx.status().equals(HttpStatus.METHOD_NOT_ALLOWED))) {
|
||||||
|
ctx.redirect("/index.html");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.options("*", ctx -> ctx.status(HttpStatus.OK));
|
||||||
|
|
||||||
app.routes(() -> {
|
app.routes(() -> {
|
||||||
path("server", () -> {
|
path("api", () -> {
|
||||||
crud("allowed/{id}", new AllowedCrudHandler(this.serverDBService));
|
path("servers", () -> {
|
||||||
crud("configs/{id}", new ConfigCrudHandler(this.serverDBService));
|
crud("configs/{id}", new ConfigCrudHandler(this.serverDBService));
|
||||||
});
|
});
|
||||||
path("user", () -> {
|
path("users", () -> {
|
||||||
crud("allowed/{id}", new AllowedUserCrudHandler(this.userDBService));
|
|
||||||
crud("configs/{id}", new ConfigUserCrudHandler(this.userDBService));
|
crud("configs/{id}", new ConfigUserCrudHandler(this.userDBService));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.start(this.javalinConfig.port());
|
app.start(this.port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package de.hhhammer.dchat.db;
|
package de.hhhammer.dchat.db;
|
||||||
|
|
||||||
import de.hhhammer.dchat.db.models.server.AllowedServer;
|
|
||||||
import de.hhhammer.dchat.db.models.server.ServerConfig;
|
import de.hhhammer.dchat.db.models.server.ServerConfig;
|
||||||
import de.hhhammer.dchat.db.models.server.ServerMessage;
|
import de.hhhammer.dchat.db.models.server.ServerMessage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -25,116 +24,7 @@ public class ServerDBService {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowed(long serverId) {
|
public Optional<ServerConfig> getConfig(String serverId) {
|
||||||
var getAllowedServerSql = """
|
|
||||||
SELECT * FROM allowed_servers WHERE server_id = ?
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(getAllowedServerSql)
|
|
||||||
) {
|
|
||||||
pstmt.setLong(1, serverId);
|
|
||||||
ResultSet result = pstmt.executeQuery();
|
|
||||||
Iterable<AllowedServer> iterable = () -> new ResultSetIterator<>(result, new AllowedServer.AllowedServerResultSetTransformer());
|
|
||||||
return StreamSupport.stream(iterable.spliterator(), false).count() == 1;
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.error("Searching for allowed server with id: " + serverId, e);
|
|
||||||
} catch (ResultSetIteratorException e) {
|
|
||||||
logger.error("Iterating over AllowedServer ResultSet for server with id: " + serverId, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<AllowedServer> getAllowedBy(long id) throws DBException {
|
|
||||||
var getAllowedServerSql = """
|
|
||||||
SELECT * FROM allowed_servers WHERE id = ?
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(getAllowedServerSql)
|
|
||||||
) {
|
|
||||||
pstmt.setLong(1, id);
|
|
||||||
ResultSet result = pstmt.executeQuery();
|
|
||||||
Iterable<AllowedServer> iterable = () -> new ResultSetIterator<>(result, new AllowedServer.AllowedServerResultSetTransformer());
|
|
||||||
return StreamSupport.stream(iterable.spliterator(), false).findFirst();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DBException("Not found allowed server entry with id: " + id, e);
|
|
||||||
} catch (ResultSetIteratorException e) {
|
|
||||||
throw new DBException("Iterating over AllowedServer ResultSet searching for id: " + id, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<AllowedServer> getAllAllowed() throws DBException {
|
|
||||||
var getAllowedServerSql = """
|
|
||||||
SELECT * FROM allowed_servers
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(getAllowedServerSql)
|
|
||||||
) {
|
|
||||||
ResultSet result = pstmt.executeQuery();
|
|
||||||
Iterable<AllowedServer> iterable = () -> new ResultSetIterator<>(result, new AllowedServer.AllowedServerResultSetTransformer());
|
|
||||||
return StreamSupport.stream(iterable.spliterator(), false).toList();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DBException("Not found allowed server entries", e);
|
|
||||||
} catch (ResultSetIteratorException e) {
|
|
||||||
throw new DBException("Iterating over AllowedServer ResultSet", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addAllowed(AllowedServer.NewAllowedServer newAllowedServer) throws DBException {
|
|
||||||
var insertAllowedServerSql = """
|
|
||||||
INSERT INTO allowed_servers (server_id, comment) VALUES (?, ?)
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(insertAllowedServerSql)
|
|
||||||
) {
|
|
||||||
pstmt.setLong(1, newAllowedServer.serverId());
|
|
||||||
pstmt.setString(2, newAllowedServer.comment());
|
|
||||||
int affectedRows = pstmt.executeUpdate();
|
|
||||||
if (affectedRows == 0) {
|
|
||||||
logger.error("No server inserted to allowed_servers with id: " + newAllowedServer.serverId());
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DBException("Allowing new server with id: " + newAllowedServer.serverId(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateAllowed(long id, AllowedServer.NewAllowedServer newAllowedServer) throws DBException {
|
|
||||||
var insertAllowedServerSql = """
|
|
||||||
UPDATE allowed_servers SET comment = ?, server_id = ? WHERE id = ?
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(insertAllowedServerSql)
|
|
||||||
) {
|
|
||||||
pstmt.setString(1, newAllowedServer.comment());
|
|
||||||
pstmt.setLong(2, newAllowedServer.serverId());
|
|
||||||
pstmt.setLong(3, id);
|
|
||||||
int affectedRows = pstmt.executeUpdate();
|
|
||||||
if (affectedRows == 0) {
|
|
||||||
logger.error("No comment updated on server with id: " + newAllowedServer.serverId());
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DBException("Updating comment on allowed server with id: " + newAllowedServer.serverId(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteAllowed(long id) throws DBException {
|
|
||||||
var insertAllowedServerSql = """
|
|
||||||
DELETE FROM allowed_servers WHERE id = ?
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(insertAllowedServerSql)
|
|
||||||
) {
|
|
||||||
pstmt.setLong(1, id);
|
|
||||||
int affectedRows = pstmt.executeUpdate();
|
|
||||||
if (affectedRows == 0) {
|
|
||||||
logger.error("No server deleted with id: " + id);
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DBException("Deleting allowed server with id: " + id, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<ServerConfig> getConfig(long serverId) {
|
|
||||||
var getServerConfig = """
|
var getServerConfig = """
|
||||||
SELECT * FROM server_configs WHERE server_id = ?
|
SELECT * FROM server_configs WHERE server_id = ?
|
||||||
""";
|
""";
|
||||||
|
@ -142,7 +32,7 @@ public class ServerDBService {
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
||||||
) {
|
) {
|
||||||
pstmt.setLong(1, serverId);
|
pstmt.setString(1, serverId);
|
||||||
ResultSet resultSet = pstmt.executeQuery();
|
ResultSet resultSet = pstmt.executeQuery();
|
||||||
Iterable<ServerConfig> iterable = () -> new ResultSetIterator<>(resultSet, new ServerConfig.ServerConfigResultSetTransformer());
|
Iterable<ServerConfig> iterable = () -> new ResultSetIterator<>(resultSet, new ServerConfig.ServerConfigResultSetTransformer());
|
||||||
return StreamSupport.stream(iterable.spliterator(), false).findFirst();
|
return StreamSupport.stream(iterable.spliterator(), false).findFirst();
|
||||||
|
@ -199,7 +89,7 @@ public class ServerDBService {
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
||||||
) {
|
) {
|
||||||
pstmt.setLong(1, newServerConfig.serverId());
|
pstmt.setString(1, newServerConfig.serverId());
|
||||||
pstmt.setString(2, newServerConfig.systemMessage());
|
pstmt.setString(2, newServerConfig.systemMessage());
|
||||||
pstmt.setInt(3, newServerConfig.rateLimit());
|
pstmt.setInt(3, newServerConfig.rateLimit());
|
||||||
int affectedRows = pstmt.executeUpdate();
|
int affectedRows = pstmt.executeUpdate();
|
||||||
|
@ -221,7 +111,7 @@ public class ServerDBService {
|
||||||
) {
|
) {
|
||||||
pstmt.setString(1, newServerConfig.systemMessage());
|
pstmt.setString(1, newServerConfig.systemMessage());
|
||||||
pstmt.setInt(2, newServerConfig.rateLimit());
|
pstmt.setInt(2, newServerConfig.rateLimit());
|
||||||
pstmt.setLong(3, newServerConfig.serverId());
|
pstmt.setString(3, newServerConfig.serverId());
|
||||||
pstmt.setLong(4, id);
|
pstmt.setLong(4, id);
|
||||||
int affectedRows = pstmt.executeUpdate();
|
int affectedRows = pstmt.executeUpdate();
|
||||||
if (affectedRows == 0) {
|
if (affectedRows == 0) {
|
||||||
|
@ -250,7 +140,7 @@ public class ServerDBService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int countMessagesInLastMinute(long serverId) {
|
public int countMessagesInLastMinute(String serverId) {
|
||||||
var getServerConfig = """
|
var getServerConfig = """
|
||||||
SELECT count(*) FROM server_messages WHERE server_id = ? AND time <= ? and time >= ?
|
SELECT count(*) FROM server_messages WHERE server_id = ? AND time <= ? and time >= ?
|
||||||
""";
|
""";
|
||||||
|
@ -258,7 +148,7 @@ public class ServerDBService {
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
||||||
) {
|
) {
|
||||||
pstmt.setLong(1, serverId);
|
pstmt.setString(1, serverId);
|
||||||
var now = Instant.now();
|
var now = Instant.now();
|
||||||
pstmt.setTimestamp(2, Timestamp.from(now));
|
pstmt.setTimestamp(2, Timestamp.from(now));
|
||||||
pstmt.setTimestamp(3, Timestamp.from(now.minus(1, ChronoUnit.MINUTES)));
|
pstmt.setTimestamp(3, Timestamp.from(now.minus(1, ChronoUnit.MINUTES)));
|
||||||
|
@ -282,7 +172,7 @@ public class ServerDBService {
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
||||||
) {
|
) {
|
||||||
pstmt.setLong(1, serverMessage.serverId());
|
pstmt.setString(1, serverMessage.serverId());
|
||||||
pstmt.setLong(2, serverMessage.userId());
|
pstmt.setLong(2, serverMessage.userId());
|
||||||
pstmt.setInt(3, serverMessage.tokens());
|
pstmt.setInt(3, serverMessage.tokens());
|
||||||
int affectedRows = pstmt.executeUpdate();
|
int affectedRows = pstmt.executeUpdate();
|
||||||
|
@ -294,7 +184,7 @@ public class ServerDBService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long tokensOfLast30Days(long serverId) {
|
public long tokensOfLast30Days(String serverId) {
|
||||||
var countTokensOfLast30Days = """
|
var countTokensOfLast30Days = """
|
||||||
SELECT sum(tokens) FROM server_messages WHERE server_id = ? AND time < ? AND time >= ?
|
SELECT sum(tokens) FROM server_messages WHERE server_id = ? AND time < ? AND time >= ?
|
||||||
""";
|
""";
|
||||||
|
@ -302,7 +192,7 @@ public class ServerDBService {
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
PreparedStatement pstmt = con.prepareStatement(countTokensOfLast30Days)
|
PreparedStatement pstmt = con.prepareStatement(countTokensOfLast30Days)
|
||||||
) {
|
) {
|
||||||
pstmt.setLong(1, serverId);
|
pstmt.setString(1, serverId);
|
||||||
var now = Instant.now();
|
var now = Instant.now();
|
||||||
pstmt.setTimestamp(2, Timestamp.from(now));
|
pstmt.setTimestamp(2, Timestamp.from(now));
|
||||||
pstmt.setTimestamp(3, Timestamp.from(now.minus(30, ChronoUnit.DAYS)));
|
pstmt.setTimestamp(3, Timestamp.from(now.minus(30, ChronoUnit.DAYS)));
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package de.hhhammer.dchat.db;
|
package de.hhhammer.dchat.db;
|
||||||
|
|
||||||
import de.hhhammer.dchat.db.models.user.AllowedUser;
|
|
||||||
import de.hhhammer.dchat.db.models.user.UserConfig;
|
import de.hhhammer.dchat.db.models.user.UserConfig;
|
||||||
import de.hhhammer.dchat.db.models.user.UserMessage;
|
import de.hhhammer.dchat.db.models.user.UserMessage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -25,115 +24,7 @@ public class UserDBService {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowed(long userId) {
|
public Optional<UserConfig> getConfig(String userId) {
|
||||||
var getAllowedServerSql = """
|
|
||||||
SELECT * FROM allowed_users WHERE user_id = ?
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(getAllowedServerSql)
|
|
||||||
) {
|
|
||||||
pstmt.setLong(1, userId);
|
|
||||||
ResultSet result = pstmt.executeQuery();
|
|
||||||
Iterable<AllowedUser> iterable = () -> new ResultSetIterator<>(result, new AllowedUser.AllowedUserResultSetTransformer());
|
|
||||||
return StreamSupport.stream(iterable.spliterator(), false).count() == 1;
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.error("Searching for allowed user with id: " + userId, e);
|
|
||||||
} catch (ResultSetIteratorException e) {
|
|
||||||
logger.error("Iterating over AllowedServer ResultSet for user with id: " + userId, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<AllowedUser> getAllowedBy(long id) throws DBException {
|
|
||||||
var getAllowedServerSql = """
|
|
||||||
SELECT * FROM allowed_users WHERE id = ?
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(getAllowedServerSql)
|
|
||||||
) {
|
|
||||||
pstmt.setLong(1, id);
|
|
||||||
ResultSet result = pstmt.executeQuery();
|
|
||||||
Iterable<AllowedUser> iterable = () -> new ResultSetIterator<>(result, new AllowedUser.AllowedUserResultSetTransformer());
|
|
||||||
return StreamSupport.stream(iterable.spliterator(), false).findFirst();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DBException("Searching for allowed with id: " + id, e);
|
|
||||||
} catch (ResultSetIteratorException e) {
|
|
||||||
throw new DBException("Iterating over AllowedServer ResultSet with id: " + id, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<AllowedUser> getAllAllowed() throws DBException {
|
|
||||||
var getAllowedServerSql = """
|
|
||||||
SELECT * FROM allowed_users
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(getAllowedServerSql)
|
|
||||||
) {
|
|
||||||
ResultSet result = pstmt.executeQuery();
|
|
||||||
Iterable<AllowedUser> iterable = () -> new ResultSetIterator<>(result, new AllowedUser.AllowedUserResultSetTransformer());
|
|
||||||
return StreamSupport.stream(iterable.spliterator(), false).toList();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DBException("Searching all allowed users", e);
|
|
||||||
} catch (ResultSetIteratorException e) {
|
|
||||||
throw new DBException("Iterating over all AllowedServer ResultSet ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addAllowed(AllowedUser.NewAllowedUser newAllowedUser) throws DBException {
|
|
||||||
var insertAllowedServerSql = """
|
|
||||||
INSERT INTO allowed_users (user_id, comment) VALUES (?, ?)
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(insertAllowedServerSql)
|
|
||||||
) {
|
|
||||||
pstmt.setLong(1, newAllowedUser.userId());
|
|
||||||
pstmt.setString(2, newAllowedUser.comment());
|
|
||||||
int affectedRows = pstmt.executeUpdate();
|
|
||||||
if (affectedRows == 0) {
|
|
||||||
logger.error("No server inserted to allowed_users with id: " + newAllowedUser.userId());
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DBException("Allowing new user with id: " + newAllowedUser.userId(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateAllowed(long id, AllowedUser.NewAllowedUser newAllowedUser) throws DBException {
|
|
||||||
var insertAllowedServerSql = """
|
|
||||||
UPDATE allowed_users SET comment = ? WHERE id = ?
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(insertAllowedServerSql)
|
|
||||||
) {
|
|
||||||
pstmt.setString(1, newAllowedUser.comment());
|
|
||||||
pstmt.setLong(2, id);
|
|
||||||
int affectedRows = pstmt.executeUpdate();
|
|
||||||
if (affectedRows == 0) {
|
|
||||||
logger.error("No comment updated on user with id: " + newAllowedUser.userId());
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DBException("Updating comment on allowed user with id: " + id, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteAllowed(long id) throws DBException {
|
|
||||||
var insertAllowedServerSql = """
|
|
||||||
DELETE FROM allowed_users WHERE id = ?
|
|
||||||
""";
|
|
||||||
try (Connection con = DriverManager.getConnection(this.jdbcConnectionString, this.username, this.password);
|
|
||||||
PreparedStatement pstmt = con.prepareStatement(insertAllowedServerSql)
|
|
||||||
) {
|
|
||||||
pstmt.setLong(1, id);
|
|
||||||
int affectedRows = pstmt.executeUpdate();
|
|
||||||
if (affectedRows == 0) {
|
|
||||||
logger.error("No user deleted with id: " + id);
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new DBException("Deleting allowed user with id: " + id, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<UserConfig> getConfig(long userId) {
|
|
||||||
var getServerConfig = """
|
var getServerConfig = """
|
||||||
SELECT * FROM user_configs WHERE user_id = ?
|
SELECT * FROM user_configs WHERE user_id = ?
|
||||||
""";
|
""";
|
||||||
|
@ -141,7 +32,7 @@ public class UserDBService {
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
||||||
) {
|
) {
|
||||||
pstmt.setLong(1, userId);
|
pstmt.setString(1, userId);
|
||||||
ResultSet resultSet = pstmt.executeQuery();
|
ResultSet resultSet = pstmt.executeQuery();
|
||||||
Iterable<UserConfig> iterable = () -> new ResultSetIterator<>(resultSet, new UserConfig.UserConfigResultSetTransformer());
|
Iterable<UserConfig> iterable = () -> new ResultSetIterator<>(resultSet, new UserConfig.UserConfigResultSetTransformer());
|
||||||
return StreamSupport.stream(iterable.spliterator(), false).findFirst();
|
return StreamSupport.stream(iterable.spliterator(), false).findFirst();
|
||||||
|
@ -199,7 +90,7 @@ public class UserDBService {
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
||||||
) {
|
) {
|
||||||
pstmt.setLong(1, newUserConfig.userId());
|
pstmt.setString(1, newUserConfig.userId());
|
||||||
pstmt.setString(2, newUserConfig.systemMessage());
|
pstmt.setString(2, newUserConfig.systemMessage());
|
||||||
pstmt.setInt(3, newUserConfig.contextLength());
|
pstmt.setInt(3, newUserConfig.contextLength());
|
||||||
pstmt.setInt(4, newUserConfig.rateLimit());
|
pstmt.setInt(4, newUserConfig.rateLimit());
|
||||||
|
@ -214,7 +105,7 @@ public class UserDBService {
|
||||||
|
|
||||||
public void updateConfig(long id, UserConfig.NewUserConfig newUserConfig) throws DBException {
|
public void updateConfig(long id, UserConfig.NewUserConfig newUserConfig) throws DBException {
|
||||||
var getServerConfig = """
|
var getServerConfig = """
|
||||||
UPDATE user_configs SET system_message = ?, context_length = ?, rate_limit = ? WHERE id = ?
|
UPDATE user_configs SET system_message = ?, context_length = ?, rate_limit = ?, user_id = ? WHERE id = ?
|
||||||
""";
|
""";
|
||||||
try (Connection con = DriverManager
|
try (Connection con = DriverManager
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
|
@ -223,7 +114,8 @@ public class UserDBService {
|
||||||
pstmt.setString(1, newUserConfig.systemMessage());
|
pstmt.setString(1, newUserConfig.systemMessage());
|
||||||
pstmt.setInt(2, newUserConfig.rateLimit());
|
pstmt.setInt(2, newUserConfig.rateLimit());
|
||||||
pstmt.setLong(3, newUserConfig.contextLength());
|
pstmt.setLong(3, newUserConfig.contextLength());
|
||||||
pstmt.setLong(4, id);
|
pstmt.setString(4, newUserConfig.userId());
|
||||||
|
pstmt.setLong(5, id);
|
||||||
int affectedRows = pstmt.executeUpdate();
|
int affectedRows = pstmt.executeUpdate();
|
||||||
if (affectedRows == 0) {
|
if (affectedRows == 0) {
|
||||||
logger.error("No config update with id: " + id);
|
logger.error("No config update with id: " + id);
|
||||||
|
@ -251,7 +143,7 @@ public class UserDBService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int countMessagesInLastMinute(long userId) {
|
public int countMessagesInLastMinute(String userId) {
|
||||||
var getServerConfig = """
|
var getServerConfig = """
|
||||||
SELECT count(*) FROM user_messages WHERE user_id = ? AND time <= ? and time >= ?
|
SELECT count(*) FROM user_messages WHERE user_id = ? AND time <= ? and time >= ?
|
||||||
""";
|
""";
|
||||||
|
@ -259,7 +151,7 @@ public class UserDBService {
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
||||||
) {
|
) {
|
||||||
pstmt.setLong(1, userId);
|
pstmt.setString(1, userId);
|
||||||
var now = Instant.now();
|
var now = Instant.now();
|
||||||
pstmt.setTimestamp(2, Timestamp.from(now));
|
pstmt.setTimestamp(2, Timestamp.from(now));
|
||||||
pstmt.setTimestamp(3, Timestamp.from(now.minus(1, ChronoUnit.MINUTES)));
|
pstmt.setTimestamp(3, Timestamp.from(now.minus(1, ChronoUnit.MINUTES)));
|
||||||
|
@ -283,7 +175,7 @@ public class UserDBService {
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
PreparedStatement pstmt = con.prepareStatement(getServerConfig)
|
||||||
) {
|
) {
|
||||||
pstmt.setLong(1, newUserMessage.userId());
|
pstmt.setString(1, newUserMessage.userId());
|
||||||
pstmt.setString(2, newUserMessage.question());
|
pstmt.setString(2, newUserMessage.question());
|
||||||
pstmt.setString(3, newUserMessage.answer());
|
pstmt.setString(3, newUserMessage.answer());
|
||||||
pstmt.setInt(4, newUserMessage.tokens());
|
pstmt.setInt(4, newUserMessage.tokens());
|
||||||
|
@ -296,7 +188,7 @@ public class UserDBService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long tokensOfLast30Days(long userId) {
|
public long tokensOfLast30Days(String userId) {
|
||||||
var countTokensOfLast30Days = """
|
var countTokensOfLast30Days = """
|
||||||
SELECT sum(tokens) FROM user_messages WHERE user_id = ? AND time < ? AND time >= ?
|
SELECT sum(tokens) FROM user_messages WHERE user_id = ? AND time < ? AND time >= ?
|
||||||
""";
|
""";
|
||||||
|
@ -304,7 +196,7 @@ public class UserDBService {
|
||||||
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
PreparedStatement pstmt = con.prepareStatement(countTokensOfLast30Days)
|
PreparedStatement pstmt = con.prepareStatement(countTokensOfLast30Days)
|
||||||
) {
|
) {
|
||||||
pstmt.setLong(1, userId);
|
pstmt.setString(1, userId);
|
||||||
var now = Instant.now();
|
var now = Instant.now();
|
||||||
pstmt.setTimestamp(2, Timestamp.from(now));
|
pstmt.setTimestamp(2, Timestamp.from(now));
|
||||||
pstmt.setTimestamp(3, Timestamp.from(now.minus(30, ChronoUnit.DAYS)));
|
pstmt.setTimestamp(3, Timestamp.from(now.minus(30, ChronoUnit.DAYS)));
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
package de.hhhammer.dchat.db.models.server;
|
|
||||||
|
|
||||||
import de.hhhammer.dchat.db.ResultSetTransformer;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
public record AllowedServer(long id, long serverId, Instant time, @Nullable String comment) {
|
|
||||||
|
|
||||||
public static class AllowedServerResultSetTransformer implements ResultSetTransformer<AllowedServer> {
|
|
||||||
@Override
|
|
||||||
public AllowedServer transform(ResultSet resultSet) throws SQLException {
|
|
||||||
var id = resultSet.getLong("id");
|
|
||||||
var serverId = resultSet.getLong("server_id");
|
|
||||||
var time = resultSet.getTimestamp("time").toInstant();
|
|
||||||
var comment = resultSet.getString("comment");
|
|
||||||
return new AllowedServer(id, serverId, time, comment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record NewAllowedServer(long serverId, @Nullable String comment) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +1,29 @@
|
||||||
package de.hhhammer.dchat.db.models.server;
|
package de.hhhammer.dchat.db.models.server;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import de.hhhammer.dchat.db.ResultSetTransformer;
|
import de.hhhammer.dchat.db.ResultSetTransformer;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
public record ServerConfig(long id, long serverId, String systemMessage, int rateLimit) {
|
public record ServerConfig(long id, String serverId, String systemMessage, int rateLimit, Instant time) {
|
||||||
|
|
||||||
public static class ServerConfigResultSetTransformer implements ResultSetTransformer<ServerConfig> {
|
public static class ServerConfigResultSetTransformer implements ResultSetTransformer<ServerConfig> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServerConfig transform(ResultSet resultSet) throws SQLException {
|
public ServerConfig transform(ResultSet resultSet) throws SQLException {
|
||||||
var id = resultSet.getLong("id");
|
var id = resultSet.getLong("id");
|
||||||
var serverId = resultSet.getLong("server_id");
|
var serverId = resultSet.getString("server_id");
|
||||||
var systemMessage = resultSet.getString("system_message");
|
var systemMessage = resultSet.getString("system_message");
|
||||||
var rateLimit = resultSet.getInt("rate_limit");
|
var rateLimit = resultSet.getInt("rate_limit");
|
||||||
return new ServerConfig(id, serverId, systemMessage, rateLimit);
|
var time = resultSet.getTimestamp("time").toInstant();
|
||||||
|
return new ServerConfig(id, serverId, systemMessage, rateLimit, time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record NewServerConfig(long serverId, String systemMessage, @Nullable int rateLimit) {
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public record NewServerConfig(String serverId, String systemMessage, @Nullable int rateLimit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
package de.hhhammer.dchat.db.models.server;
|
package de.hhhammer.dchat.db.models.server;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import de.hhhammer.dchat.db.ResultSetTransformer;
|
import de.hhhammer.dchat.db.ResultSetTransformer;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
public record ServerMessage(long id, long serverId, long userId, int tokens, Instant time) {
|
public record ServerMessage(long id, String serverId, long userId, int tokens, Instant time) {
|
||||||
|
|
||||||
public static class ServerMessageResultSetTransformer implements ResultSetTransformer<ServerMessage> {
|
public static class ServerMessageResultSetTransformer implements ResultSetTransformer<ServerMessage> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServerMessage transform(ResultSet resultSet) throws SQLException {
|
public ServerMessage transform(ResultSet resultSet) throws SQLException {
|
||||||
var id = resultSet.getLong("id");
|
var id = resultSet.getLong("id");
|
||||||
var serverId = resultSet.getLong("server_id");
|
var serverId = resultSet.getString("server_id");
|
||||||
var userId = resultSet.getLong("user_id");
|
var userId = resultSet.getLong("user_id");
|
||||||
var tokens = resultSet.getInt("tokens");
|
var tokens = resultSet.getInt("tokens");
|
||||||
var time = resultSet.getTimestamp("time").toInstant();
|
var time = resultSet.getTimestamp("time").toInstant();
|
||||||
|
@ -21,6 +22,7 @@ public record ServerMessage(long id, long serverId, long userId, int tokens, Ins
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record NewServerMessage(long serverId, long userId, int tokens) {
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public record NewServerMessage(String serverId, long userId, int tokens) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
package de.hhhammer.dchat.db.models.user;
|
|
||||||
|
|
||||||
import de.hhhammer.dchat.db.ResultSetTransformer;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
public record AllowedUser(long id, long userId, Instant time, @Nullable String comment) {
|
|
||||||
|
|
||||||
public static class AllowedUserResultSetTransformer implements ResultSetTransformer<AllowedUser> {
|
|
||||||
@Override
|
|
||||||
public AllowedUser transform(ResultSet resultSet) throws SQLException {
|
|
||||||
var id = resultSet.getLong("id");
|
|
||||||
var userId = resultSet.getLong("user_id");
|
|
||||||
var time = resultSet.getTimestamp("time").toInstant();
|
|
||||||
var comment = resultSet.getString("comment");
|
|
||||||
return new AllowedUser(id, userId, time, comment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record NewAllowedUser(long userId, @Nullable String comment) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +1,31 @@
|
||||||
package de.hhhammer.dchat.db.models.user;
|
package de.hhhammer.dchat.db.models.user;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import de.hhhammer.dchat.db.ResultSetTransformer;
|
import de.hhhammer.dchat.db.ResultSetTransformer;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
public record UserConfig(long id, long userId, String systemMessage, int contextLength, int rateLimit) {
|
public record UserConfig(long id, String userId, String systemMessage, int contextLength, int rateLimit, Instant time) {
|
||||||
|
|
||||||
public static class UserConfigResultSetTransformer implements ResultSetTransformer<UserConfig> {
|
public static class UserConfigResultSetTransformer implements ResultSetTransformer<UserConfig> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserConfig transform(ResultSet resultSet) throws SQLException {
|
public UserConfig transform(ResultSet resultSet) throws SQLException {
|
||||||
var id = resultSet.getLong("id");
|
var id = resultSet.getLong("id");
|
||||||
var userId = resultSet.getLong("user_id");
|
var userId = resultSet.getString("user_id");
|
||||||
var systemMessage = resultSet.getString("system_message");
|
var systemMessage = resultSet.getString("system_message");
|
||||||
var contextLength = resultSet.getInt("context_length");
|
var contextLength = resultSet.getInt("context_length");
|
||||||
var rateLimit = resultSet.getInt("rate_limit");
|
var rateLimit = resultSet.getInt("rate_limit");
|
||||||
return new UserConfig(id, userId, systemMessage, contextLength, rateLimit);
|
var time = resultSet.getTimestamp("time").toInstant();
|
||||||
|
return new UserConfig(id, userId, systemMessage, contextLength, rateLimit, time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record NewUserConfig(long userId, String systemMessage, @Nullable int contextLength,
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public record NewUserConfig(String userId, String systemMessage, @Nullable int contextLength,
|
||||||
@Nullable int rateLimit) {
|
@Nullable int rateLimit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
package de.hhhammer.dchat.db.models.user;
|
package de.hhhammer.dchat.db.models.user;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import de.hhhammer.dchat.db.ResultSetTransformer;
|
import de.hhhammer.dchat.db.ResultSetTransformer;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
public record UserMessage(long id, long userId, String question, String answer, int tokens, Instant time) {
|
public record UserMessage(long id, String userId, String question, String answer, int tokens, Instant time) {
|
||||||
|
|
||||||
public static class UserMessageResultSetTransformer implements ResultSetTransformer<UserMessage> {
|
public static class UserMessageResultSetTransformer implements ResultSetTransformer<UserMessage> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserMessage transform(ResultSet resultSet) throws SQLException {
|
public UserMessage transform(ResultSet resultSet) throws SQLException {
|
||||||
var id = resultSet.getLong("id");
|
var id = resultSet.getLong("id");
|
||||||
var userId = resultSet.getLong("user_id");
|
var userId = resultSet.getString("user_id");
|
||||||
var question = resultSet.getString("question");
|
var question = resultSet.getString("question");
|
||||||
var answer = resultSet.getString("answer");
|
var answer = resultSet.getString("answer");
|
||||||
var tokens = resultSet.getInt("tokens");
|
var tokens = resultSet.getInt("tokens");
|
||||||
|
@ -22,6 +23,7 @@ public record UserMessage(long id, long userId, String question, String answer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record NewUserMessage(long userId, String question, String answer, int tokens) {
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public record NewUserMessage(String userId, String question, String answer, int tokens) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class MessageCreateHandler implements MessageCreateListener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.messageHandler.exceedsRate(event)) {
|
if (this.messageHandler.exceedsRate(event)) {
|
||||||
event.getChannel().sendMessage("Rate limit hit - cooling down now...");
|
event.getChannel().sendMessage("Rate limit hit - cooling down...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.messageHandler.handle(event);
|
this.messageHandler.handle(event);
|
||||||
|
|
|
@ -29,6 +29,8 @@ public class ServerMessageHandler implements MessageHandler {
|
||||||
@Override
|
@Override
|
||||||
public void handle(MessageCreateEvent event) {
|
public void handle(MessageCreateEvent event) {
|
||||||
String content = extractContent(event);
|
String content = extractContent(event);
|
||||||
|
var serverId = event.getServer().get().getId();
|
||||||
|
var systemMessage = this.serverDBService.getConfig(String.valueOf(serverId)).get().systemMessage();
|
||||||
var request = event.getMessage().getType() == MessageType.REPLY ?
|
var request = event.getMessage().getType() == MessageType.REPLY ?
|
||||||
new ChatGPTRequestBuilder()
|
new ChatGPTRequestBuilder()
|
||||||
.contextRequest(event.getMessage()
|
.contextRequest(event.getMessage()
|
||||||
|
@ -37,8 +39,8 @@ public class ServerMessageHandler implements MessageHandler {
|
||||||
.flatMap(m -> m)
|
.flatMap(m -> m)
|
||||||
.map(Message::getReadableContent)
|
.map(Message::getReadableContent)
|
||||||
.stream().toList(),
|
.stream().toList(),
|
||||||
content) :
|
content, systemMessage) :
|
||||||
new ChatGPTRequestBuilder().simpleRequest(content);
|
new ChatGPTRequestBuilder().simpleRequest(content, systemMessage);
|
||||||
try {
|
try {
|
||||||
var response = this.chatGPTService.submit(request);
|
var response = this.chatGPTService.submit(request);
|
||||||
if (response.choices().size() < 1) {
|
if (response.choices().size() < 1) {
|
||||||
|
@ -56,21 +58,22 @@ public class ServerMessageHandler implements MessageHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAllowed(MessageCreateEvent event) {
|
public boolean isAllowed(MessageCreateEvent event) {
|
||||||
if (event.getServer().isPresent()) {
|
if (event.getServer().isEmpty()) {
|
||||||
var serverId = event.getServer().get().getId();
|
|
||||||
var allowed = this.serverDBService.isAllowed(serverId);
|
|
||||||
if (!allowed) {
|
|
||||||
logger.debug("Not allowed with id: " + serverId);
|
|
||||||
}
|
|
||||||
return allowed;
|
|
||||||
}
|
|
||||||
// only support server messages
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var serverId = event.getServer().get().getId();
|
||||||
|
var config = this.serverDBService.getConfig(String.valueOf(serverId));
|
||||||
|
if (config.isEmpty()) {
|
||||||
|
logger.debug("Not allowed with id: " + serverId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean exceedsRate(MessageCreateEvent event) {
|
public boolean exceedsRate(MessageCreateEvent event) {
|
||||||
var serverId = event.getServer().get().getId();
|
var serverId = String.valueOf(event.getServer().get().getId());
|
||||||
var config = this.serverDBService.getConfig(serverId);
|
var config = this.serverDBService.getConfig(serverId);
|
||||||
if (config.isEmpty()) {
|
if (config.isEmpty()) {
|
||||||
logger.error("Missing configuration for server with id: " + serverId);
|
logger.error("Missing configuration for server with id: " + serverId);
|
||||||
|
@ -91,7 +94,7 @@ public class ServerMessageHandler implements MessageHandler {
|
||||||
var serverId = event.getServer().map(DiscordEntity::getId).get();
|
var serverId = event.getServer().map(DiscordEntity::getId).get();
|
||||||
var userId = event.getMessageAuthor().getId();
|
var userId = event.getMessageAuthor().getId();
|
||||||
|
|
||||||
var serverMessage = new ServerMessage.NewServerMessage(serverId, userId, tokens);
|
var serverMessage = new ServerMessage.NewServerMessage(String.valueOf(serverId), userId, tokens);
|
||||||
this.serverDBService.addMessage(serverMessage);
|
this.serverDBService.addMessage(serverMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,9 @@ public class UserMessageHandler implements MessageHandler {
|
||||||
@Override
|
@Override
|
||||||
public void handle(MessageCreateEvent event) {
|
public void handle(MessageCreateEvent event) {
|
||||||
String content = event.getReadableMessageContent();
|
String content = event.getReadableMessageContent();
|
||||||
var request = new ChatGPTRequestBuilder().simpleRequest(content);
|
var userId = event.getMessageAuthor().getId();
|
||||||
|
var systemMessage = this.userDBService.getConfig(String.valueOf(userId)).get().systemMessage();
|
||||||
|
var request = new ChatGPTRequestBuilder().simpleRequest(content, systemMessage);
|
||||||
try {
|
try {
|
||||||
var response = this.chatGPTService.submit(request);
|
var response = this.chatGPTService.submit(request);
|
||||||
if (response.choices().size() < 1) {
|
if (response.choices().size() < 1) {
|
||||||
|
@ -47,16 +49,17 @@ public class UserMessageHandler implements MessageHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
var userId = event.getMessageAuthor().getId();
|
var userId = event.getMessageAuthor().getId();
|
||||||
var allowed = this.userDBService.isAllowed(userId);
|
var config = this.userDBService.getConfig(String.valueOf(userId));
|
||||||
if (!allowed) {
|
if (config.isEmpty()) {
|
||||||
logger.debug("Not allowed with id: " + userId);
|
logger.debug("Not allowed with id: " + userId);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return allowed;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean exceedsRate(MessageCreateEvent event) {
|
public boolean exceedsRate(MessageCreateEvent event) {
|
||||||
var userId = event.getMessageAuthor().getId();
|
var userId = String.valueOf(event.getMessageAuthor().getId());
|
||||||
var config = this.userDBService.getConfig(userId);
|
var config = this.userDBService.getConfig(userId);
|
||||||
if (config.isEmpty()) {
|
if (config.isEmpty()) {
|
||||||
logger.error("Missing configuration for userId with id: " + userId);
|
logger.error("Missing configuration for userId with id: " + userId);
|
||||||
|
@ -76,7 +79,7 @@ public class UserMessageHandler implements MessageHandler {
|
||||||
private void logUserMessage(MessageCreateEvent event, String question, String answer, int tokens) {
|
private void logUserMessage(MessageCreateEvent event, String question, String answer, int tokens) {
|
||||||
var userId = event.getMessageAuthor().getId();
|
var userId = event.getMessageAuthor().getId();
|
||||||
|
|
||||||
var userMessage = new UserMessage.NewUserMessage(userId, question, answer, tokens);
|
var userMessage = new UserMessage.NewUserMessage(String.valueOf(userId), question, answer, tokens);
|
||||||
this.userDBService.addMessage(userMessage);
|
this.userDBService.addMessage(userMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package de.hhhammer.dchat.migration;
|
||||||
|
|
||||||
|
public class DBMigrationException extends Exception {
|
||||||
|
public DBMigrationException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package de.hhhammer.dchat.migration;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
public class MigrationExecutor {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(MigrationExecutor.class);
|
||||||
|
private final String jdbcConnectionString;
|
||||||
|
private final String username;
|
||||||
|
private final String password;
|
||||||
|
|
||||||
|
public MigrationExecutor(String jdbcConnectionString, String username, String password) {
|
||||||
|
this.jdbcConnectionString = jdbcConnectionString;
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void migrate(InputStream input) throws DBMigrationException {
|
||||||
|
try (Connection con = DriverManager
|
||||||
|
.getConnection(this.jdbcConnectionString, this.username, this.password);
|
||||||
|
Statement stmp = con.createStatement();
|
||||||
|
) {
|
||||||
|
String content = new String(input.readAllBytes(), StandardCharsets.UTF_8);
|
||||||
|
stmp.execute(content);
|
||||||
|
} catch (SQLException | IOException e) {
|
||||||
|
throw new DBMigrationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,14 +7,11 @@ import java.util.List;
|
||||||
|
|
||||||
public class ChatGPTRequestBuilder {
|
public class ChatGPTRequestBuilder {
|
||||||
private final String model = "gpt-3.5-turbo";
|
private final String model = "gpt-3.5-turbo";
|
||||||
private final String systemMessage = """
|
|
||||||
You are Jarvis, a helpful and friendly AI. People interact with you over Discord, a chatting platform. Your default language to answer is German. You format your responses in markdown and your answers don´t need to be formal.
|
|
||||||
""";
|
|
||||||
|
|
||||||
public ChatGPTRequestBuilder() {
|
public ChatGPTRequestBuilder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatGPTRequest simpleRequest(String content) {
|
public ChatGPTRequest simpleRequest(String content, String systemMessage) {
|
||||||
return new ChatGPTRequest(
|
return new ChatGPTRequest(
|
||||||
model,
|
model,
|
||||||
List.of(new ChatGPTRequest.Message("system", systemMessage), new ChatGPTRequest.Message("user", content)),
|
List.of(new ChatGPTRequest.Message("system", systemMessage), new ChatGPTRequest.Message("user", content)),
|
||||||
|
@ -22,7 +19,7 @@ public class ChatGPTRequestBuilder {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatGPTRequest contextRequest(List<String> contextMessages, String message) {
|
public ChatGPTRequest contextRequest(List<String> contextMessages, String message, String systemMessage) {
|
||||||
List<ChatGPTRequest.Message> messages = new ArrayList<>();
|
List<ChatGPTRequest.Message> messages = new ArrayList<>();
|
||||||
messages.add(new ChatGPTRequest.Message("system", systemMessage));
|
messages.add(new ChatGPTRequest.Message("system", systemMessage));
|
||||||
var context = contextMessages.stream()
|
var context = contextMessages.stream()
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
package de.hhhammer.dchat.web;
|
|
||||||
|
|
||||||
public record JavalinConfig(int port, String username, String password) {
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
package de.hhhammer.dchat.web.server;
|
|
||||||
|
|
||||||
import de.hhhammer.dchat.db.DBException;
|
|
||||||
import de.hhhammer.dchat.db.ServerDBService;
|
|
||||||
import de.hhhammer.dchat.db.models.server.AllowedServer;
|
|
||||||
import io.javalin.apibuilder.CrudHandler;
|
|
||||||
import io.javalin.http.Context;
|
|
||||||
import io.javalin.http.HttpStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class AllowedCrudHandler implements CrudHandler {
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(AllowedCrudHandler.class);
|
|
||||||
|
|
||||||
private final ServerDBService serverDBService;
|
|
||||||
|
|
||||||
public AllowedCrudHandler(ServerDBService serverDBService) {
|
|
||||||
this.serverDBService = serverDBService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void create(@NotNull Context context) {
|
|
||||||
var body = context.bodyAsClass(AllowedServer.NewAllowedServer.class);
|
|
||||||
try {
|
|
||||||
this.serverDBService.addAllowed(body);
|
|
||||||
} catch (DBException e) {
|
|
||||||
logger.error("Adding new allowed server", e);
|
|
||||||
context.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
context.status(HttpStatus.CREATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(@NotNull Context context, @NotNull String s) {
|
|
||||||
try {
|
|
||||||
this.serverDBService.deleteAllowed(Long.parseLong(s));
|
|
||||||
context.status(HttpStatus.NO_CONTENT);
|
|
||||||
} catch (DBException e) {
|
|
||||||
logger.error("Deleting server with id: " + s, e);
|
|
||||||
context.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getAll(@NotNull Context context) {
|
|
||||||
try {
|
|
||||||
var allowedServers = this.serverDBService.getAllAllowed();
|
|
||||||
context.json(allowedServers);
|
|
||||||
} catch (DBException e) {
|
|
||||||
logger.error("Getting all allowed servers", e);
|
|
||||||
context.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getOne(@NotNull Context context, @NotNull String s) {
|
|
||||||
var id = Long.parseLong(s);
|
|
||||||
try {
|
|
||||||
var server = this.serverDBService.getAllowedBy(id);
|
|
||||||
if (server.isEmpty()) {
|
|
||||||
context.status(HttpStatus.NOT_FOUND);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
context.json(server.get());
|
|
||||||
} catch (DBException e) {
|
|
||||||
logger.error("Searching with id: " + s, e);
|
|
||||||
context.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(@NotNull Context context, @NotNull String idString) {
|
|
||||||
var newAllowedServer = context.bodyAsClass(AllowedServer.NewAllowedServer.class);
|
|
||||||
var id = Long.parseLong(idString);
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.serverDBService.updateAllowed(id, newAllowedServer);
|
|
||||||
} catch (DBException e) {
|
|
||||||
logger.error("Updating allowed server with id: " + idString, e);
|
|
||||||
context.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
package de.hhhammer.dchat.web.user;
|
|
||||||
|
|
||||||
import de.hhhammer.dchat.db.DBException;
|
|
||||||
import de.hhhammer.dchat.db.UserDBService;
|
|
||||||
import de.hhhammer.dchat.db.models.user.AllowedUser;
|
|
||||||
import io.javalin.apibuilder.CrudHandler;
|
|
||||||
import io.javalin.http.Context;
|
|
||||||
import io.javalin.http.HttpStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class AllowedUserCrudHandler implements CrudHandler {
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(AllowedUserCrudHandler.class);
|
|
||||||
|
|
||||||
private final UserDBService userDBService;
|
|
||||||
|
|
||||||
public AllowedUserCrudHandler(UserDBService userDBService) {
|
|
||||||
this.userDBService = userDBService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void create(@NotNull Context context) {
|
|
||||||
var body = context.bodyAsClass(AllowedUser.NewAllowedUser.class);
|
|
||||||
try {
|
|
||||||
this.userDBService.addAllowed(body);
|
|
||||||
} catch (DBException e) {
|
|
||||||
logger.error("Adding new server configuration", e);
|
|
||||||
context.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
context.status(HttpStatus.CREATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(@NotNull Context context, @NotNull String s) {
|
|
||||||
try {
|
|
||||||
this.userDBService.deleteAllowed(Long.parseLong(s));
|
|
||||||
context.status(HttpStatus.NO_CONTENT);
|
|
||||||
} catch (DBException e) {
|
|
||||||
logger.error("Deleting configuration with id: " + s, e);
|
|
||||||
context.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getAll(@NotNull Context context) {
|
|
||||||
try {
|
|
||||||
var allowedServers = this.userDBService.getAllAllowed();
|
|
||||||
context.json(allowedServers);
|
|
||||||
} catch (DBException e) {
|
|
||||||
logger.error("Getting all server configs", e);
|
|
||||||
context.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getOne(@NotNull Context context, @NotNull String s) {
|
|
||||||
var id = Long.parseLong(s);
|
|
||||||
try {
|
|
||||||
var server = this.userDBService.getAllowedBy(id);
|
|
||||||
if (server.isEmpty()) {
|
|
||||||
context.status(HttpStatus.NOT_FOUND);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
context.json(server.get());
|
|
||||||
} catch (DBException e) {
|
|
||||||
logger.error("Searching for config with id: " + s, e);
|
|
||||||
context.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(@NotNull Context context, @NotNull String idString) {
|
|
||||||
var body = context.bodyAsClass(AllowedUser.NewAllowedUser.class);
|
|
||||||
var id = Long.parseLong(idString);
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.userDBService.updateAllowed(id, body);
|
|
||||||
} catch (DBException e) {
|
|
||||||
logger.error("Updating allowed server with id: " + idString, e);
|
|
||||||
context.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -86,4 +86,39 @@ BEGIN;
|
||||||
ALTER TABLE user_configs
|
ALTER TABLE user_configs
|
||||||
ADD COLUMN IF NOT EXISTS context_length INT NOT NULL DEFAULT 5;
|
ADD COLUMN IF NOT EXISTS context_length INT NOT NULL DEFAULT 5;
|
||||||
|
|
||||||
COMMIT
|
COMMIT;
|
||||||
|
|
||||||
|
-- Add time to config to know when it was added
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE server_configs
|
||||||
|
ADD COLUMN IF NOT EXISTS time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||||
|
|
||||||
|
ALTER TABLE user_configs
|
||||||
|
ADD COLUMN IF NOT EXISTS time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- Remove obsolete allowed tables that are being replaced the configs tables
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS allowed_servers;
|
||||||
|
DROP TABLE IF EXISTS allowed_users;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE server_configs
|
||||||
|
ALTER COLUMN server_id TYPE text USING server_id::text;
|
||||||
|
|
||||||
|
ALTER TABLE server_messages
|
||||||
|
ALTER COLUMN server_id TYPE text USING server_id::text;
|
||||||
|
|
||||||
|
ALTER TABLE user_configs
|
||||||
|
ALTER COLUMN user_id TYPE text USING user_id::text;
|
||||||
|
|
||||||
|
ALTER TABLE user_messages
|
||||||
|
ALTER COLUMN user_id TYPE text USING user_id::text;
|
||||||
|
|
||||||
|
COMMIT;
|
12
ui/.containerignore
Normal file
12
ui/.containerignore
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
*
|
||||||
|
!Caddyfile
|
||||||
|
!package*.json
|
||||||
|
!postcss.config.js
|
||||||
|
!tailwind.config.js
|
||||||
|
!env.d..ts
|
||||||
|
!vite.config.ts
|
||||||
|
!tsconfig.json
|
||||||
|
!tsconfig.node.json
|
||||||
|
!index.html
|
||||||
|
!public/
|
||||||
|
!src/
|
28
ui/.gitignore
vendored
Normal file
28
ui/.gitignore
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
coverage
|
||||||
|
*.local
|
||||||
|
|
||||||
|
/cypress/videos/
|
||||||
|
/cypress/screenshots/
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
3
ui/.vscode/extensions.json
vendored
Normal file
3
ui/.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||||
|
}
|
11
ui/Caddyfile
Normal file
11
ui/Caddyfile
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{$SITE_ADDRESS} {
|
||||||
|
basicauth * {
|
||||||
|
{$AUTH_PASSWORD} {$AUTH_PASSWORD}
|
||||||
|
}
|
||||||
|
|
||||||
|
encode zstd gzip
|
||||||
|
|
||||||
|
root * /app
|
||||||
|
try_files {path} /index.html
|
||||||
|
file_server
|
||||||
|
}
|
16
ui/Containerfile
Normal file
16
ui/Containerfile
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
FROM docker.io/node:18-slim AS build
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./package* .
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build-only
|
||||||
|
|
||||||
|
FROM docker.io/caddy:2-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./Caddyfile /
|
||||||
|
COPY --from=build /app/dist /app
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
CMD ["caddy", "run", "--config", "/Caddyfile"]
|
40
ui/README.md
Normal file
40
ui/README.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# dchat-ui
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 in Vite.
|
||||||
|
|
||||||
|
## Recommended IDE Setup
|
||||||
|
|
||||||
|
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
||||||
|
|
||||||
|
## Type Support for `.vue` Imports in TS
|
||||||
|
|
||||||
|
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
|
||||||
|
|
||||||
|
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
|
||||||
|
|
||||||
|
1. Disable the built-in TypeScript Extension
|
||||||
|
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
||||||
|
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
||||||
|
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
|
||||||
|
|
||||||
|
## Customize configuration
|
||||||
|
|
||||||
|
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||||
|
|
||||||
|
## Project Setup
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compile and Hot-Reload for Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Type-Check, Compile and Minify for Production
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run build
|
||||||
|
```
|
31
ui/build.sh
Executable file
31
ui/build.sh
Executable file
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
REPO="git.hhhammer.de/hamburghammer/dchat-ui"
|
||||||
|
AUTHORS="Augusto Dwenger J. <dwenger@posteo.de>"
|
||||||
|
URL="https://${REPO}"
|
||||||
|
VENDOR="hamburghammer"
|
||||||
|
TITLE="dchat-ui"
|
||||||
|
DESCRIPTION="The Web-UI for dchat a Discord bot to chat with ChatGPT from OpenAI"
|
||||||
|
CREATED=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
REVISION=$(git rev-parse HEAD)
|
||||||
|
|
||||||
|
IMAGE_LATEST="${REPO}:latest"
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
podman build \
|
||||||
|
$DOCKER_BUILD_ARGS \
|
||||||
|
-t $IMAGE_LATEST \
|
||||||
|
--label "org.opencontainers.image.revision=${REVISION}" \
|
||||||
|
--label "org.opencontainers.image.version=${TAG}" \
|
||||||
|
--label "org.opencontainers.image.authors=${AUTHORS}" \
|
||||||
|
--label "org.opencontainers.image.created=${CREATED}" \
|
||||||
|
--label "org.opencontainers.image.source=${URL}" \
|
||||||
|
--label "org.opencontainers.image.vendor=${VENDOR}" \
|
||||||
|
--label "org.opencontainers.image.title=${TITLE}" \
|
||||||
|
--label "org.opencontainers.image.description=${DESCRIPTION}" \
|
||||||
|
. || exit $?
|
||||||
|
|
||||||
|
if [ "$PUSH_LATEST" == "1" ]; then
|
||||||
|
podman push "${IMAGE_LATEST}"
|
||||||
|
fi
|
||||||
|
|
1
ui/env.d.ts
vendored
Normal file
1
ui/env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="vite/client" />
|
13
ui/index.html
Normal file
13
ui/index.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="icon" href="/favicon.ico">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Vite App</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
5046
ui/package-lock.json
generated
Normal file
5046
ui/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
29
ui/package.json
Normal file
29
ui/package.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "dchat-ui",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "run-p type-check build-only",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"build-only": "vite build",
|
||||||
|
"type-check": "vue-tsc --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"daisyui": "^2.51.5",
|
||||||
|
"vue": "^3.2.47",
|
||||||
|
"vue-router": "^4.1.6"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.14.2",
|
||||||
|
"@vitejs/plugin-vue": "^4.0.0",
|
||||||
|
"@vue/tsconfig": "^0.1.3",
|
||||||
|
"autoprefixer": "^10.4.14",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"postcss": "^8.4.22",
|
||||||
|
"tailwindcss": "^3.3.1",
|
||||||
|
"typescript": "~4.8.4",
|
||||||
|
"vite": "^4.1.4",
|
||||||
|
"vue-tsc": "^1.2.0"
|
||||||
|
}
|
||||||
|
}
|
6
ui/postcss.config.js
Normal file
6
ui/postcss.config.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
BIN
ui/public/favicon.ico
Normal file
BIN
ui/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
37
ui/src/App.vue
Normal file
37
ui/src/App.vue
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { RouterView } from 'vue-router'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<header>
|
||||||
|
<div class="navbar bg-base-100">
|
||||||
|
<div class="flex-1">
|
||||||
|
<a class="btn btn-ghost normal-case text-xl">
|
||||||
|
<RouterLink to="/">dchat</RouterLink>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="flex-none">
|
||||||
|
<ul class="menu menu-horizontal px-1">
|
||||||
|
<li class="m-1">
|
||||||
|
<RouterLink to="/servers">Servers</RouterLink>
|
||||||
|
</li>
|
||||||
|
<li class="m-1">
|
||||||
|
<RouterLink to="/users">Users</RouterLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<Suspense>
|
||||||
|
<RouterView />
|
||||||
|
</Suspense>
|
||||||
|
<footer class="footer footer-center p-4 bg-base-300 text-base-content">
|
||||||
|
<div>
|
||||||
|
<p>Copyright © 2023 Augusto Dwenger J.</p>
|
||||||
|
<p>This website is licensed under the <a href="https://git.hhhammer.de/hamburghammer/dchat/raw/branch/main/LICENSE"
|
||||||
|
class="link">MIT License</a>
|
||||||
|
and uses open source software. View the <a href="https://git.hhhammer.de/hamburghammer/dchat" class="link">source
|
||||||
|
code</a> on Forgejo.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</template>
|
3
ui/src/assets/base.css
Normal file
3
ui/src/assets/base.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
1
ui/src/assets/main.css
Normal file
1
ui/src/assets/main.css
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@import './base.css';
|
36
ui/src/components/ModalComponent.vue
Normal file
36
ui/src/components/ModalComponent.vue
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
export interface Props {
|
||||||
|
modalId: string | number,
|
||||||
|
openModal: { class: string, label: string },
|
||||||
|
isDestructive?: boolean,
|
||||||
|
submitAction: () => Promise<void>,
|
||||||
|
cancelAction?: () => Promise<void>,
|
||||||
|
onLoadAction?: () => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
isDestructive: false,
|
||||||
|
cancelAction: () => Promise.resolve(),
|
||||||
|
onLoadAction: () => Promise.resolve()
|
||||||
|
})
|
||||||
|
const modalId = "modal-" + props.modalId
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<!-- The button to open modal -->
|
||||||
|
<label v-bind:for="modalId" v-bind:class="props.openModal.class" @click="props.onLoadAction">
|
||||||
|
{{ props.openModal.label }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<!-- Put this part before </body> tag -->
|
||||||
|
<input type="checkbox" v-bind:id="modalId" class="modal-toggle" />
|
||||||
|
<div class="modal">
|
||||||
|
<div class="modal-box">
|
||||||
|
<slot />
|
||||||
|
<div class="modal-action">
|
||||||
|
<label v-if="props.isDestructive" v-bind:for="modalId" class="btn btn-error" @click="props.submitAction">Delete</label>
|
||||||
|
<label v-else v-bind:for="modalId" class="btn btn-success" @click="props.submitAction">Save</label>
|
||||||
|
<label v-bind:for="modalId" class="btn" @click="props.cancelAction">Cancel</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
35
ui/src/components/TableComponent.vue
Normal file
35
ui/src/components/TableComponent.vue
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
// index arg being the index number of the row
|
||||||
|
type ActionFunction = (index: number) => void
|
||||||
|
const { tableHeader, tableRows, showActions } = defineProps<{
|
||||||
|
tableHeader: string[],
|
||||||
|
tableRows: any[][],
|
||||||
|
showActions: boolean
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="table w-full">
|
||||||
|
<!-- head -->
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<template v-for="header in tableHeader">
|
||||||
|
<th>{{ header }}</th>
|
||||||
|
</template>
|
||||||
|
<th v-if="showActions">Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- row -->
|
||||||
|
<tr v-for="row in tableRows">
|
||||||
|
<template v-for="data in row">
|
||||||
|
<th>{{ data }}</th>
|
||||||
|
</template>
|
||||||
|
<th>
|
||||||
|
<slot name="action" :row="row" />
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
4
ui/src/components/TestComponent.vue
Normal file
4
ui/src/components/TestComponent.vue
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const {id} = defineProps<{id: any}>()
|
||||||
|
debugger
|
||||||
|
</script>
|
34
ui/src/components/server/AddServerConfig.vue
Normal file
34
ui/src/components/server/AddServerConfig.vue
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ModalComponent from '@/components/ModalComponent.vue';
|
||||||
|
import type { ServerConfig } from "@/models/server";
|
||||||
|
import { addConfig } from '@/services/ServerConfigs';
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const modalId = "addServerConfig"
|
||||||
|
|
||||||
|
const newConfig = ref<ServerConfig | Record<string, never>>({})
|
||||||
|
const submitAction = async () => {
|
||||||
|
if (!newConfig) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return addConfig(newConfig.value as ServerConfig)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ModalComponent :modalId="modalId" :openModal="{ class: 'btn btn-circle btn-success', label: 'Add' }"
|
||||||
|
:submitAction="submitAction">
|
||||||
|
<h1 class="text-xl normal-case">Add Server Config</h1>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">Server ID</label>
|
||||||
|
<input v-model="newConfig.serverId" class="input input-bordered w-full max-w-xs" />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">System Message</label>
|
||||||
|
<textarea v-model="newConfig.systemMessage" class="textarea textarea-bordered w-2/3 h-2/3" />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">Rate Limit</label>
|
||||||
|
<input v-model.number="newConfig.rateLimit" class="input input-bordered w-full max-w-xs" />
|
||||||
|
</div>
|
||||||
|
</ModalComponent>
|
||||||
|
</template>
|
17
ui/src/components/server/DeleteServerConfig.vue
Normal file
17
ui/src/components/server/DeleteServerConfig.vue
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ModalComponent from '@/components/ModalComponent.vue';
|
||||||
|
import { deleteConfig } from '@/services/ServerConfigs';
|
||||||
|
|
||||||
|
const { id } = defineProps<{ id: number }>()
|
||||||
|
|
||||||
|
const submitAction = async () => {
|
||||||
|
return deleteConfig(id)
|
||||||
|
}
|
||||||
|
const modalId = "delete-" + id
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ModalComponent :modalId="modalId" :openModal="{ class: 'btn btn-sm btn-error m-1', label: 'Delete' }"
|
||||||
|
:submitAction="submitAction" :isDestructive="true">
|
||||||
|
<h1 class="text-xl normal-case">Are you sure?</h1>
|
||||||
|
</ModalComponent>
|
||||||
|
</template>
|
41
ui/src/components/server/EditServerConfig.vue
Normal file
41
ui/src/components/server/EditServerConfig.vue
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ModalComponent from '@/components/ModalComponent.vue';
|
||||||
|
import { getConfig } from '@/services/ServerConfigs'
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import type { ServerConfig } from '@/models/server';
|
||||||
|
import { updateConfig } from '@/services/ServerConfigs';
|
||||||
|
|
||||||
|
const { id } = defineProps<{ id: number }>()
|
||||||
|
|
||||||
|
const configToEdit = ref<ServerConfig | Record<string, never>>({})
|
||||||
|
const submitAction = async () => {
|
||||||
|
return updateConfig(id, configToEdit.value as ServerConfig)
|
||||||
|
|
||||||
|
}
|
||||||
|
const onLoadAction = async () => {
|
||||||
|
configToEdit.value = await getConfig(id)
|
||||||
|
}
|
||||||
|
const modalId = "edit-" + id
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ModalComponent :modalId="modalId" :openModal="{ class: 'btn btn-sm btn-info m-1', label: 'Edit' }"
|
||||||
|
:submitAction="submitAction" :onLoadAction="onLoadAction">
|
||||||
|
<h1 class="text-xl normal-case">Edit Server Config</h1>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">ID</label>
|
||||||
|
<input v-model.number="configToEdit.id" class="input input-bordered w-full max-w-xs" disabled />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">Server ID</label>
|
||||||
|
<input v-model="configToEdit.serverId" class="input input-bordered w-full max-w-xs" />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">System Message</label>
|
||||||
|
<textarea v-model="configToEdit.systemMessage" class="textarea textarea-bordered w-2/3 h-2/3" />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">Rate Limit</label>
|
||||||
|
<input v-model.number="configToEdit.rateLimit" class="input input-bordered w-full max-w-xs" />
|
||||||
|
</div>
|
||||||
|
</ModalComponent>
|
||||||
|
</template>
|
35
ui/src/components/user/AddUserConfig.vue
Normal file
35
ui/src/components/user/AddUserConfig.vue
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ModalComponent from '@/components/ModalComponent.vue';
|
||||||
|
import type { UserConfig } from "@/models/user";
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { addConfig } from '@/services/UserConfigs';
|
||||||
|
|
||||||
|
const modalId = "addUserConfig"
|
||||||
|
|
||||||
|
const newConfig = ref<UserConfig | Record<string, never>>({})
|
||||||
|
const submitAction = async () => {
|
||||||
|
return addConfig(newConfig.value as UserConfig)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ModalComponent :modalId="modalId" :openModal="{ class: 'btn btn-circle btn-success', label: 'Add' }"
|
||||||
|
:submitAction="submitAction">
|
||||||
|
<h1 class="text-xl normal-case">Add User Config</h1>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">User ID</label>
|
||||||
|
<input v-model="newConfig.userId" class="input input-bordered w-full max-w-xs" />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">System Message</label>
|
||||||
|
<textarea v-model="newConfig.systemMessage" class="textarea textarea-bordered w-2/3 h-2/3" />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">Context Length</label>
|
||||||
|
<input v-model.number="newConfig.contextLength" class="input input-bordered w-full max-w-xs" />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">Rate Limit</label>
|
||||||
|
<input v-model.number="newConfig.rateLimit" class="input input-bordered w-full max-w-xs" />
|
||||||
|
</div>
|
||||||
|
</ModalComponent>
|
||||||
|
</template>
|
17
ui/src/components/user/DeleteUserConfig.vue
Normal file
17
ui/src/components/user/DeleteUserConfig.vue
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ModalComponent from '@/components/ModalComponent.vue';
|
||||||
|
import { deleteConfig } from '@/services/UserConfigs';
|
||||||
|
|
||||||
|
const { id } = defineProps<{ id: number }>()
|
||||||
|
|
||||||
|
const submitAction = async () => {
|
||||||
|
return deleteConfig(id)
|
||||||
|
}
|
||||||
|
const modalId = "delete-" + id
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ModalComponent :modalId="modalId" :openModal="{ class: 'btn btn-sm btn-error m-1', label: 'Delete' }"
|
||||||
|
:submitAction="submitAction" :isDestructive="true">
|
||||||
|
<h1 class="text-xl normal-case">Are you sure?</h1>
|
||||||
|
</ModalComponent>
|
||||||
|
</template>
|
44
ui/src/components/user/EditUserConfig.vue
Normal file
44
ui/src/components/user/EditUserConfig.vue
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ModalComponent from '@/components/ModalComponent.vue';
|
||||||
|
import { getConfig } from '@/services/UserConfigs'
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import type { UserConfig } from '@/models/user';
|
||||||
|
import { updateConfig } from '@/services/UserConfigs';
|
||||||
|
|
||||||
|
const { id } = defineProps<{ id: number }>()
|
||||||
|
|
||||||
|
const configToEdit = ref<UserConfig | Record<string, never>>({})
|
||||||
|
const submitAction = async () => {
|
||||||
|
return updateConfig(id, configToEdit.value as UserConfig)
|
||||||
|
}
|
||||||
|
const onLoadAction = async () => {
|
||||||
|
configToEdit.value = await getConfig(id)
|
||||||
|
}
|
||||||
|
const modalId = "edit-" + id
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ModalComponent :modalId="modalId" :openModal="{ class: 'btn btn-sm btn-info m-1', label: 'Edit' }"
|
||||||
|
:submitAction="submitAction" :onLoadAction="onLoadAction">
|
||||||
|
<h1 class="text-xl normal-case">Edit User Config</h1>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">ID</label>
|
||||||
|
<input v-model.number="configToEdit.id" class="input input-bordered w-full max-w-xs" disabled />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">User ID</label>
|
||||||
|
<input v-model="configToEdit.userId" class="input input-bordered w-full max-w-xs" />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">System Message</label>
|
||||||
|
<textarea v-model="configToEdit.systemMessage" class="textarea textarea-bordered w-2/3 h-2/3" />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">Context Length</label>
|
||||||
|
<input v-model.number="configToEdit.contextLength" class="input input-bordered w-full max-w-xs" />
|
||||||
|
</div>
|
||||||
|
<div class="m-2">
|
||||||
|
<label class="mr-4">Rate Limit</label>
|
||||||
|
<input v-model.number="configToEdit.rateLimit" class="input input-bordered w-full max-w-xs" />
|
||||||
|
</div>
|
||||||
|
</ModalComponent>
|
||||||
|
</template>
|
11
ui/src/main.ts
Normal file
11
ui/src/main.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { createApp } from 'vue'
|
||||||
|
import App from '@/App.vue'
|
||||||
|
import router from './router'
|
||||||
|
|
||||||
|
import './assets/main.css'
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
|
||||||
|
app.use(router)
|
||||||
|
|
||||||
|
app.mount('#app')
|
8
ui/src/models/server.ts
Normal file
8
ui/src/models/server.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export type ServerConfig = {
|
||||||
|
id: number,
|
||||||
|
serverId: string,
|
||||||
|
systemMessage: string,
|
||||||
|
rateLimit: number,
|
||||||
|
time: string
|
||||||
|
}
|
||||||
|
|
8
ui/src/models/user.ts
Normal file
8
ui/src/models/user.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export type UserConfig = {
|
||||||
|
id: number,
|
||||||
|
userId: string,
|
||||||
|
systemMessage: string,
|
||||||
|
contextLength: number,
|
||||||
|
rateLimit: number,
|
||||||
|
time: string
|
||||||
|
}
|
39
ui/src/router/index.ts
Normal file
39
ui/src/router/index.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
import HomeView from '@/views/HomeView.vue'
|
||||||
|
import IndexServersView from '@/views/servers/IndexServersView.vue'
|
||||||
|
import ServerConfigsView from '@/views/servers/ServerConfigsView.vue'
|
||||||
|
import IndexUsersView from '@/views/users/IndexUsersView.vue'
|
||||||
|
import UserConfigsView from '@/views/users/UserConfigsView.vue'
|
||||||
|
|
||||||
|
const routerConfig = createRouter({
|
||||||
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'home',
|
||||||
|
component: HomeView
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/servers',
|
||||||
|
name: 'servers',
|
||||||
|
component: IndexServersView
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/servers/configs',
|
||||||
|
name: 'serverConfigs',
|
||||||
|
component: ServerConfigsView
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/users',
|
||||||
|
name: 'users',
|
||||||
|
component: IndexUsersView
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/users/configs',
|
||||||
|
name: 'userConfigs',
|
||||||
|
component: UserConfigsView
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export default routerConfig
|
39
ui/src/services/ServerConfigs.ts
Normal file
39
ui/src/services/ServerConfigs.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import type { ServerConfig } from "@/models/server";
|
||||||
|
|
||||||
|
const configUrl = "http://localhost:7070/api/servers/configs/"
|
||||||
|
|
||||||
|
export async function getConfigs(): Promise<ServerConfig[]> {
|
||||||
|
return fetch(configUrl)
|
||||||
|
.then(shouldBeSuccess)
|
||||||
|
.then(res => res.json())
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getConfig(id: number): Promise<ServerConfig> {
|
||||||
|
return fetch(configUrl + id)
|
||||||
|
.then(shouldBeSuccess)
|
||||||
|
.then(res => res.json())
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateConfig(id: number, config: ServerConfig): Promise<void> {
|
||||||
|
return fetch(configUrl + id, { method: "PATCH", body: JSON.stringify(config) })
|
||||||
|
.then(shouldBeSuccess)
|
||||||
|
.then()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addConfig(config: ServerConfig): Promise<void> {
|
||||||
|
debugger
|
||||||
|
return fetch(configUrl, { method: "POST", body: JSON.stringify(config) })
|
||||||
|
.then(shouldBeSuccess)
|
||||||
|
.then()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteConfig(id: number): Promise<void> {
|
||||||
|
return fetch(configUrl + id, { method: "DELETE" })
|
||||||
|
.then(shouldBeSuccess)
|
||||||
|
.then()
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldBeSuccess(res: Response): Response {
|
||||||
|
if (res.status >= 200 && res.status < 300) return res
|
||||||
|
throw new Error(`Expected success status code but got: ${res.status} ${res.statusText}`)
|
||||||
|
}
|
40
ui/src/services/UserConfigs.ts
Normal file
40
ui/src/services/UserConfigs.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import type { UserConfig } from '@/models/user'
|
||||||
|
|
||||||
|
const configUrl = "http://localhost:7070/api/users/configs/"
|
||||||
|
|
||||||
|
export async function getConfigs(): Promise<UserConfig[]> {
|
||||||
|
return fetch(configUrl)
|
||||||
|
.then(shouldBeSuccess)
|
||||||
|
.then(res => res.json())
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getConfig(id: number): Promise<UserConfig> {
|
||||||
|
return fetch(configUrl + id)
|
||||||
|
.then(shouldBeSuccess)
|
||||||
|
.then(res => res.json())
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateConfig(id: number, config: UserConfig): Promise<void> {
|
||||||
|
return fetch(configUrl + id, { method: "PATCH", body: JSON.stringify(config) })
|
||||||
|
.then(shouldBeSuccess)
|
||||||
|
.then()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addConfig(config: UserConfig): Promise<void> {
|
||||||
|
debugger
|
||||||
|
return fetch(configUrl, { method: "POST", body: JSON.stringify(config) })
|
||||||
|
.then(shouldBeSuccess)
|
||||||
|
.then()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteConfig(id: number): Promise<void> {
|
||||||
|
return fetch(configUrl + id, { method: "DELETE" })
|
||||||
|
.then(shouldBeSuccess)
|
||||||
|
.then()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function shouldBeSuccess(res: Response): Response {
|
||||||
|
if (res.status >= 200 && res.status < 300) return res
|
||||||
|
throw new Error(`Expected success status code but got: ${res.status} ${res.statusText}`)
|
||||||
|
}
|
13
ui/src/views/HomeView.vue
Normal file
13
ui/src/views/HomeView.vue
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<template>
|
||||||
|
<h1 class="text-xl normal-case m-5">Overview</h1>
|
||||||
|
<div class="flex justify-center m-4">
|
||||||
|
<div class="flex flex-col space-y-2">
|
||||||
|
<RouterLink to="/servers">
|
||||||
|
<button class="btn btn-wide btn-outline">Servers</button>
|
||||||
|
</RouterLink>
|
||||||
|
<RouterLink to="/users">
|
||||||
|
<button class="btn btn-wide btn-outline">Users</button>
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
5
ui/src/views/UsersView.vue
Normal file
5
ui/src/views/UsersView.vue
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
12
ui/src/views/servers/IndexServersView.vue
Normal file
12
ui/src/views/servers/IndexServersView.vue
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<h1 class="text-xl normal-case m-5">Server overview</h1>
|
||||||
|
<div class="flex justify-center m-4">
|
||||||
|
<div class="flex flex-col space-y-2">
|
||||||
|
<RouterLink to="/servers/configs">
|
||||||
|
<button class="btn btn-wide btn-outline">Configs</button>
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
27
ui/src/views/servers/ServerConfigsView.vue
Normal file
27
ui/src/views/servers/ServerConfigsView.vue
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import TableComponent from '@/components/TableComponent.vue';
|
||||||
|
import AddServerConfig from '@/components/server/AddServerConfig.vue';
|
||||||
|
import { getConfigs } from '@/services/ServerConfigs'
|
||||||
|
import EditServerConfig from '@/components/server/EditServerConfig.vue';
|
||||||
|
import DeleteServerConfig from '@/components/server/DeleteServerConfig.vue';
|
||||||
|
|
||||||
|
const trimSystemMessage = (str: string) => str.length > 50 ? str.slice(0, 47) + "..." : str
|
||||||
|
|
||||||
|
const serverConfigs = await getConfigs()
|
||||||
|
|
||||||
|
const tableHeader = ["ID", "Server ID", "System Message", "Rate limit", "Created"]
|
||||||
|
const tableRows = serverConfigs.map(config => [config.id, config.serverId, trimSystemMessage(config.systemMessage), config.rateLimit, config.time])
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-between m-5">
|
||||||
|
<h1 class="text-xl normal-case">Server Configs</h1>
|
||||||
|
<AddServerConfig />
|
||||||
|
</div>
|
||||||
|
<TableComponent v-if="serverConfigs.length" :tableHeader="tableHeader" :tableRows="tableRows" :showActions="true">
|
||||||
|
<template #action="action">
|
||||||
|
<EditServerConfig :id="action.row[0]" />
|
||||||
|
<DeleteServerConfig :id="action.row[0]" />
|
||||||
|
</template>
|
||||||
|
</TableComponent>
|
||||||
|
<p v-else class="m-5">No server configs</p>
|
||||||
|
</template>
|
12
ui/src/views/users/IndexUsersView.vue
Normal file
12
ui/src/views/users/IndexUsersView.vue
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<h1 class="text-xl normal-case m-5">Server overview</h1>
|
||||||
|
<div class="flex justify-center m-4">
|
||||||
|
<div class="flex flex-col space-y-2">
|
||||||
|
<RouterLink to="/users/configs">
|
||||||
|
<button class="btn btn-wide btn-outline">Configs</button>
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
27
ui/src/views/users/UserConfigsView.vue
Normal file
27
ui/src/views/users/UserConfigsView.vue
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import TableComponent from '@/components/TableComponent.vue';
|
||||||
|
import AddUserConfig from '@/components/user/AddUserConfig.vue';
|
||||||
|
import { getConfigs } from '@/services/UserConfigs'
|
||||||
|
import EditUserConfig from '@/components/user/EditUserConfig.vue';
|
||||||
|
import DeleteServerConfig from '@/components/server/DeleteServerConfig.vue';
|
||||||
|
|
||||||
|
const trimSystemMessage = (str: string) => str.length > 50 ? str.slice(0, 47) + "..." : str
|
||||||
|
|
||||||
|
const userConfigs = await getConfigs()
|
||||||
|
|
||||||
|
const tableHeader = ["ID", "User ID", "System Message", "Context Length", "Rate limit", "Created"]
|
||||||
|
const tableRows = userConfigs.map(config => [config.id, config.userId, trimSystemMessage(config.systemMessage), config.contextLength, config.rateLimit, config.time])
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-between m-5">
|
||||||
|
<h1 class="text-xl normal-case">User Configs</h1>
|
||||||
|
<AddUserConfig />
|
||||||
|
</div>
|
||||||
|
<TableComponent v-if="userConfigs.length" :tableHeader="tableHeader" :tableRows="tableRows" :showActions="true">
|
||||||
|
<template #action="action">
|
||||||
|
<EditUserConfig :id="action.row[0]" />
|
||||||
|
<DeleteServerConfig :id="action.row[0]" />
|
||||||
|
</template>
|
||||||
|
</TableComponent>
|
||||||
|
<p v-else class="m-5">No user configs</p>
|
||||||
|
</template>
|
9
ui/tailwind.config.js
Normal file
9
ui/tailwind.config.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [require("daisyui")],
|
||||||
|
}
|
||||||
|
|
16
ui/tsconfig.json
Normal file
16
ui/tsconfig.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.web.json",
|
||||||
|
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.node.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
8
ui/tsconfig.node.json
Normal file
8
ui/tsconfig.node.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.node.json",
|
||||||
|
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"types": ["node"]
|
||||||
|
}
|
||||||
|
}
|
14
ui/vite.config.ts
Normal file
14
ui/vite.config.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
Loading…
Reference in a new issue