From 4c1699c31465fe1b51f8266550bf91df03ea33fe Mon Sep 17 00:00:00 2001 From: Timo Date: Sat, 25 May 2024 15:47:14 +0200 Subject: [PATCH] added get endpoint for posts by id --- .../de/anxietyprime/swajodel/JodelPost.java | 17 +- .../de/anxietyprime/swajodel/Reaction.java | 6 - .../de/anxietyprime/swajodel/Reactions.java | 11 ++ .../java/de/anxietyprime/swajodel/Routes.java | 145 +++++++++++++++--- 4 files changed, 148 insertions(+), 31 deletions(-) delete mode 100644 src/main/java/de/anxietyprime/swajodel/Reaction.java create mode 100644 src/main/java/de/anxietyprime/swajodel/Reactions.java diff --git a/src/main/java/de/anxietyprime/swajodel/JodelPost.java b/src/main/java/de/anxietyprime/swajodel/JodelPost.java index 2051356..4b9b6d0 100644 --- a/src/main/java/de/anxietyprime/swajodel/JodelPost.java +++ b/src/main/java/de/anxietyprime/swajodel/JodelPost.java @@ -4,6 +4,8 @@ import java.util.Date; import java.util.Optional; import java.util.Vector; +import java.sql.*; + public class JodelPost { // id of the post public Long id; @@ -24,7 +26,7 @@ public class JodelPost { // the own reaction (null = none, true = positive, false = negative) public Optional reaction; // all other reactions - public Reaction reactions; + public Reactions reactions; // anonymize function to recursively anonymize the posts public void anonymize(Optional> idCache) { @@ -70,8 +72,15 @@ public class JodelPost { return false; } - // constructor with private authorID - public JodelPost(long authorID) { - this.authorID = authorID; + // constructor from + public JodelPost(ResultSet rs) throws SQLException { + // add all other information to the post + this.authorID = rs.getLong("author"); + this.id = rs.getLong("id"); + this.title = rs.getString("title"); + this.content = rs.getString("content"); + this.date = rs.getDate("postdate"); + this.location = new Location(rs.getLong("longitude"), rs.getLong("latitude")); + this.reactions = new Reactions(rs.getLong("positive"), rs.getLong("negative")); } } \ No newline at end of file diff --git a/src/main/java/de/anxietyprime/swajodel/Reaction.java b/src/main/java/de/anxietyprime/swajodel/Reaction.java deleted file mode 100644 index 93bc789..0000000 --- a/src/main/java/de/anxietyprime/swajodel/Reaction.java +++ /dev/null @@ -1,6 +0,0 @@ -package de.anxietyprime.swajodel; - -public class Reaction { - private long positive; - private long negative; -} diff --git a/src/main/java/de/anxietyprime/swajodel/Reactions.java b/src/main/java/de/anxietyprime/swajodel/Reactions.java new file mode 100644 index 0000000..463dd81 --- /dev/null +++ b/src/main/java/de/anxietyprime/swajodel/Reactions.java @@ -0,0 +1,11 @@ +package de.anxietyprime.swajodel; + +public class Reactions { + public long positive; + public long negative; + + Reactions(long positive, long negative) { + this.positive = positive; + this.negative = negative; + } +} diff --git a/src/main/java/de/anxietyprime/swajodel/Routes.java b/src/main/java/de/anxietyprime/swajodel/Routes.java index 4e7eb88..0b3aabb 100644 --- a/src/main/java/de/anxietyprime/swajodel/Routes.java +++ b/src/main/java/de/anxietyprime/swajodel/Routes.java @@ -1,8 +1,8 @@ package de.anxietyprime.swajodel; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; import java.sql.*; @@ -13,7 +13,7 @@ import java.util.Vector; public class Routes { @GetMapping("/posts/{longitude}/{latitude}") - public Vector getPosts(@PathVariable("longitude") float longitude, @PathVariable("latitude") float latitude) { + public Vector getPostsByLocation(@PathVariable("longitude") float longitude, @PathVariable("latitude") float latitude) { // list of all posts (not comments) in range Vector posts = new Vector<>(); @@ -36,20 +36,22 @@ public class Routes { // create a new statement stmt = c.prepareStatement("WITH RECURSIVE targets AS (\n" + " SELECT\n" + - " id,\n" + - " id AS parent,\n" + - " author,\n" + - " title,\n" + - " content,\n" + - " postdate,\n" + - " postlocation[0] AS longitude,\n" + - " postlocation[1] AS latitude\n" + + " posts.id,\n" + + " posts.id AS parent,\n" + + " posts.author,\n" + + " posts.title,\n" + + " posts.content,\n" + + " posts.postdate,\n" + + " posts.postlocation[0] AS longitude,\n" + + " posts.postlocation[1] AS latitude,\n" + + " (SELECT count(*) FROM reaction WHERE reaction.post = posts.id AND positive = TRUE) AS positive,\n" + + " (SELECT count(*) FROM reaction WHERE reaction.post = posts.id AND positive = FALSE) AS negative\n" + " FROM\n" + " posts\n" + " WHERE\n" + " deleted IS NULL\n" + " AND sqrt(power(postlocation[0] - (?), 2) + power(postlocation[1] - (?), 2)) <= 10\n" + - " AND id NOT IN (SELECT child FROM comments)\n" + + " AND posts.id NOT IN (SELECT child FROM comments)\n" + " UNION\n" + " SELECT\n" + " com.child,\n" + @@ -59,7 +61,9 @@ public class Routes { " com.content,\n" + " com.postdate,\n" + " com.postlocation[0],\n" + - " com.postlocation[1]\n" + + " com.postlocation[1],\n" + + " (SELECT count(*) FROM reaction WHERE reaction.post = com.child AND positive = TRUE) AS positive,\n" + + " (SELECT count(*) FROM reaction WHERE reaction.post = com.child AND positive = FALSE) AS negative\n" + " FROM\n" + " (SELECT * FROM comments inner join posts ON comments.child = posts.id) com\n" + " inner join targets ON targets.id = com.parent\n" + @@ -75,13 +79,7 @@ public class Routes { // for all the posts found while ( rs.next() ) { // create a post from the author id - JodelPost post = new JodelPost(rs.getLong("author")); - // add all other information to the post - post.id = rs.getLong("id"); - post.title = rs.getString("title"); - post.content = rs.getString("content"); - post.date = rs.getDate("postdate"); - post.location = new Location(rs.getLong("longitude"), rs.getLong("latitude")); + JodelPost post = new JodelPost(rs); // get the posts parent long parent = rs.getLong("parent"); @@ -111,6 +109,7 @@ public class Routes { // else log the error catch ( Exception e ) { System.err.println( e.getClass().getName()+": "+ e.getMessage() ); + throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE, "Database is offline"); } // calculate anonymous IDs for the posts @@ -120,4 +119,108 @@ public class Routes { // return the posts return posts; } + + @GetMapping("/post/{id}") + public JodelPost getPostByID(@PathVariable("id") long id) { + // list of all posts (not comments) in range + Optional root_post = Optional.empty(); + + // DB connection and statement + Connection c = null; + PreparedStatement stmt = null; + + // try to get data from db + try { + // check for the driver + Class.forName("org.postgresql.Driver"); + // get the connection with credentials from env variables + c = DriverManager + .getConnection("jdbc:postgresql://"+ + System.getenv("POSTGRES_IP")+"/"+System.getenv("POSTGRES_DB"), + System.getenv("POSTGRES_USER"), System.getenv("POSTGRES_PASSWORD")); + // disable auto commits + c.setAutoCommit(false); + + // create a new statement + stmt = c.prepareStatement("WITH RECURSIVE targets AS (\n" + + " SELECT\n" + + " posts.id,\n" + + " posts.id AS parent,\n" + + " posts.author,\n" + + " posts.title,\n" + + " posts.content,\n" + + " posts.postdate,\n" + + " posts.postlocation[0] AS longitude,\n" + + " posts.postlocation[1] AS latitude,\n" + + " (SELECT count(*) FROM reaction WHERE reaction.post = posts.id AND positive = TRUE) AS positive,\n" + + " (SELECT count(*) FROM reaction WHERE reaction.post = posts.id AND positive = FALSE) AS negative\n" + + " FROM\n" + + " posts\n" + + " WHERE\n" + + " deleted IS NULL\n" + + " AND posts.id = (?)\n" + + " AND posts.id NOT IN (SELECT child FROM comments)\n" + + " UNION\n" + + " SELECT\n" + + " com.child,\n" + + " com.parent,\n" + + " com.author,\n" + + " com.title,\n" + + " com.content,\n" + + " com.postdate,\n" + + " com.postlocation[0],\n" + + " com.postlocation[1],\n" + + " (SELECT count(*) FROM reaction WHERE reaction.post = com.child AND positive = TRUE) AS positive,\n" + + " (SELECT count(*) FROM reaction WHERE reaction.post = com.child AND positive = FALSE) AS negative\n" + + " FROM\n" + + " (SELECT * FROM comments inner join posts ON comments.child = posts.id) com\n" + + " inner join targets ON targets.id = com.parent\n" + + ")\n" + + "SELECT * FROM targets;"); + + stmt.setObject(1, id); + + // query recursively for posts inside a 10km radius + ResultSet rs = stmt.executeQuery(); + + // for all the posts found + while ( rs.next() ) { + // create a post from the author id + JodelPost post = new JodelPost(rs); + + // get the posts parent + long parent = rs.getLong("parent"); + + // check if the parent is the own id + // if it is, it is a post + if (parent == post.id) { + // add the post to the posts + root_post = Optional.of(post); + } + // else it is a comment + else { + // try to add the post to parent + root_post.ifPresent(root -> root.addComment(post, parent)); + } + } + + // close all connections to db + rs.close(); + stmt.close(); + c.close(); + } + + // else log the error + catch ( Exception e ) { + System.err.println( e.getClass().getName()+": "+ e.getMessage() ); + throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE, "Database is offline"); + } + + // calculate anonymous IDs for the post + root_post.ifPresent(root -> root.anonymize(Optional.empty())); + + // return the posts + if (root_post.isEmpty()) throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No post found"); + return root_post.get(); + } }