Files
SWA-backend/src/main/java/de/anxietyprime/swajodel/Routes.java

337 lines
13 KiB
Java

package de.anxietyprime.swajodel;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.sql.*;
import java.util.Optional;
import java.util.Vector;
@RestController
public class Routes {
@GetMapping("/posts/{longitude}/{latitude}")
public Vector<JodelPost> getPostsByLocation(@PathVariable("longitude") float longitude, @PathVariable("latitude") float latitude) {
// list of all posts (not comments) in range
Vector<JodelPost> posts = new Vector<>();
// 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 sqrt(power(postlocation[0] - (?), 2) + power(postlocation[1] - (?), 2)) <= 10\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, longitude);
stmt.setObject(2, latitude);
// 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);
// check if the parent is the own id
// if it is, it is a post
if (!post.isComment()) {
// add the post to the posts
posts.add(post);
}
// else it is a comment
else {
// iterate over all posts
for (JodelPost p : posts) {
// try to add the post to a parent
p.addComment(post);
}
}
}
// 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 posts
posts.forEach(post -> {
post.anonymize(Optional.empty());
});
// return the posts
return posts;
}
@GetMapping("/post/{id}")
public JodelPost getPostByID(@PathVariable("id") long id) {
// list of all posts (not comments) in range
Optional<JodelPost> 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));
}
}
// 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();
}
@PostMapping("/posts")
public JodelPost postPost(@RequestBody JodelPost post) {
// 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("INSERT INTO Posts(author, title, content, postdate, postlocation) " +
"VALUES (?, ?, ?, ?, Point(?, ?)) RETURNING id");
stmt.setObject(1, post.getAuthorID());
stmt.setObject(2, post.title);
stmt.setObject(3, post.content);
stmt.setObject(4, post.date);
stmt.setObject(5, post.location.longitude);
stmt.setObject(6, post.location.latitude);
// insert post and get its id
ResultSet rs = stmt.executeQuery();
// get the id of the new post
rs.next();
post.id = rs.getLong("id");
// check if there is a parent
if (post.parent.isPresent()) {
// create a new statement
stmt = c.prepareStatement("INSERT INTO comments(parent, child) VALUES (?, ?)");
// fill statement
stmt.setObject(1, post.parent.get());
stmt.setObject(2, post.id);
// execute statement
stmt.execute();
}
// commit the changes
c.commit();
// close all connections to db
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");
}
// fill missing post values
if (post.parent.isEmpty()) post.parent = Optional.of(post.id);
post.reactions = new Reactions(0, 0);
post.reaction = Optional.empty();
// anonymize code
post.anonymize(Optional.empty());
return post;
}
@DeleteMapping("/post/{id}")
public void deletePost(@PathVariable long id) {
// 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("UPDATE Posts SET deleted = now() WHERE id = ? AND deleted IS NULL");
stmt.setObject(1, id);
// insert delete time
stmt.execute();
// close all connections to db
stmt.close();
c.commit();
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");
}
}
}