Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jmsundin authored Jan 25, 2024
0 parents commit e788847
Show file tree
Hide file tree
Showing 19 changed files with 1,531 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
target/
h2/
history_log.txt
testCases_log.txt
restructure_tmp/
restructured_labs/
.revature/tmp
.vscode
.idea/
76 changes: 76 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- project metadata-->
<groupId>org.revature</groupId>
<artifactId>Challenges</artifactId>
<version>1.1</version>
<!-- maven allows us to change the version of java we'd like to use -->
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<!-- maven allows us to use external dependencies from mvn repository.
meaning, we're downloading java classes that other developers have written and can
use them in our projects!-->
<dependencies>
<dependency>
<!-- junit, our framework for writing unit tests.-->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.javalin/javalin -->
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>5.0.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.0-rc1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
</dependency>
<!-- mockito allows for creating mock objects for use of testing service classes with a mock DAO. -->
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.9.0</version>
</dependency>


</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>3.0.0-M7</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

</project>
95 changes: 95 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Project: Social media blog API

## Background

When building a full-stack application, we're typically concerned with both a front end, that displays information to the user and takes in input, and a backend, that manages persisted information.

This project will be a backend for a hypothetical social media app, where we must manage our users’ accounts as well as any messages that they submit to the application. The application will function as a micro-blogging or messaging app. In our hypothetical application, any user should be able to see all of the messages posted to the site, or they can see the messages posted by a particular user. In either case, we require a backend which is able to deliver the data needed to display this information as well as process actions like logins, registrations, message creations, message updates, and message deletions.

## Database Tables

These will be provided in a sql script, and a ConnectionUtil class that will run the sql script is provided:

### Account
```
account_id integer primary key auto_increment,
username varchar(255) unique,
password varchar(255)
```

### Message
```
message_id integer primary key auto_increment,
posted_by integer,
message_text varchar(255),
time_posted_epoch long,
foreign key (posted_by) references Account(account_id)
```

# Requirements

## 1: Our API should be able to process new User registrations.

As a user, I should be able to create a new Account on the endpoint POST localhost:8080/register. The body will contain a representation of a JSON Account, but will not contain an account_id.

- The registration will be successful if and only if the username is not blank, the password is at least 4 characters long, and an Account with that username does not already exist. If all these conditions are met, the response body should contain a JSON of the Account, including its account_id. The response status should be 200 OK, which is the default. The new account should be persisted to the database.
- If the registration is not successful, the response status should be 400. (Client error)

## 2: Our API should be able to process User logins.

As a user, I should be able to verify my login on the endpoint POST localhost:8080/login. The request body will contain a JSON representation of an Account, not containing an account_id. In the future, this action may generate a Session token to allow the user to securely use the site. We will not worry about this for now.

- The login will be successful if and only if the username and password provided in the request body JSON match a real account existing on the database. If successful, the response body should contain a JSON of the account in the response body, including its account_id. The response status should be 200 OK, which is the default.
- If the login is not successful, the response status should be 401. (Unauthorized)


## 3: Our API should be able to process the creation of new messages.

As a user, I should be able to submit a new post on the endpoint POST localhost:8080/messages. The request body will contain a JSON representation of a message, which should be persisted to the database, but will not contain a message_id.

- The creation of the message will be successful if and only if the message_text is not blank, is not over 255 characters, and posted_by refers to a real, existing user. If successful, the response body should contain a JSON of the message, including its message_id. The response status should be 200, which is the default. The new message should be persisted to the database.
- If the creation of the message is not successful, the response status should be 400. (Client error)

## 4: Our API should be able to retrieve all messages.

As a user, I should be able to submit a GET request on the endpoint GET localhost:8080/messages.

- The response body should contain a JSON representation of a list containing all messages retrieved from the database. It is expected for the list to simply be empty if there are no messages. The response status should always be 200, which is the default.

## 5: Our API should be able to retrieve a message by its ID.

As a user, I should be able to submit a GET request on the endpoint GET localhost:8080/messages/{message_id}.

- The response body should contain a JSON representation of the message identified by the message_id. It is expected for the response body to simply be empty if there is no such message. The response status should always be 200, which is the default.

## 6: Our API should be able to delete a message identified by a message ID.

As a User, I should be able to submit a DELETE request on the endpoint DELETE localhost:8080/messages/{message_id}.

- The deletion of an existing message should remove an existing message from the database. If the message existed, the response body should contain the now-deleted message. The response status should be 200, which is the default.
- If the message did not exist, the response status should be 200, but the response body should be empty. This is because the DELETE verb is intended to be idempotent, ie, multiple calls to the DELETE endpoint should respond with the same type of response.

## 7: Our API should be able to update a message text identified by a message ID.

As a user, I should be able to submit a PATCH request on the endpoint PATCH localhost:8080/messages/{message_id}. The request body should contain a new message_text values to replace the message identified by message_id. The request body can not be guaranteed to contain any other information.

- The update of a message should be successful if and only if the message id already exists and the new message_text is not blank and is not over 255 characters. If the update is successful, the response body should contain the full updated message (including message_id, posted_by, message_text, and time_posted_epoch), and the response status should be 200, which is the default. The message existing on the database should have the updated message_text.
- If the update of the message is not successful for any reason, the response status should be 400. (Client error)

## 8: Our API should be able to retrieve all messages written by a particular user.

As a user, I should be able to submit a GET request on the endpoint GET localhost:8080/accounts/{account_id}/messages.

- The response body should contain a JSON representation of a list containing all messages posted by a particular user, which is retrieved from the database. It is expected for the list to simply be empty if there are no messages. The response status should always be 200, which is the default.

# Further guidance

Some classes are already complete and SHOULD NOT BE CHANGED - Integration tests, Model classes for Account and Message, a ConnectionUtil class. Changing any of these classes will likely result in the test cases being impossible to pass.

The .sql script found in src/main/resources is already complete and SHOULD NOT BE CHANGED. Changing this file will likely result in the test cases being impossible to pass.

You SHOULD be changing the SocialMediaController class to add endpoints to the StartAPI method. A main method in Main.java is also provided to allow you to run the entire application and manually play or test with the app. Changing that class will not affect the test cases at all. You could use it to perform any manual unit testing on your other classes.

You SHOULD be creating and designing DAO and Service class to allow you to complete the project. In theory, you could design the project however you like, so long as the functionality works and you are somehow persisting data to the database - but a 3-layer architecture is a robust design pattern and following help you in the long run. You can refer to prior mini-projects and course material for help on designing your application in this way.

# Good luck!
33 changes: 33 additions & 0 deletions src/main/java/Controller/SocialMediaController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package Controller;

import io.javalin.Javalin;
import io.javalin.http.Context;

/**
* TODO: You will need to write your own endpoints and handlers for your controller. The endpoints you will need can be
* found in readme.md as well as the test cases. You should
* refer to prior mini-project labs and lecture materials for guidance on how a controller may be built.
*/
public class SocialMediaController {
/**
* In order for the test cases to work, you will need to write the endpoints in the startAPI() method, as the test
* suite must receive a Javalin object from this method.
* @return a Javalin app object which defines the behavior of the Javalin controller.
*/
public Javalin startAPI() {
Javalin app = Javalin.create();
app.get("example-endpoint", this::exampleHandler);

return app;
}

/**
* This is an example handler for an example endpoint.
* @param context The Javalin Context object manages information about both the HTTP request and response.
*/
private void exampleHandler(Context context) {
context.json("sample text");
}


}
5 changes: 5 additions & 0 deletions src/main/java/DAO/todo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
You will need to design and create your own DAO classes from scratch.
You should refer to prior mini-project lab examples and course material for guidance.

Please refrain from using a 'try-with-resources' block when connecting to your database.
The ConnectionUtil provided uses a singleton, and using a try-with-resources will cause issues in the tests.
14 changes: 14 additions & 0 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Controller.SocialMediaController;
import io.javalin.Javalin;

/**
* This class is provided with a main method to allow you to manually run and test your application. This class will not
* affect your program in any way and you may write whatever code you like here.
*/
public class Main {
public static void main(String[] args) {
SocialMediaController controller = new SocialMediaController();
Javalin app = controller.startAPI();
app.start(8080);
}
}
118 changes: 118 additions & 0 deletions src/main/java/Model/Account.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package Model;

/**
* This is a class that models an Account.
*
* DO NOT CHANGE ANYTHING IN THIS CLASS
*
*/
public class Account {
/**
* An id for this Account which will be automatically generated by the database.
*/
public int account_id;
/**
* A username for this Account (must be unique and not blank)
*/
public String username;
/**
* A password for this account (must be over 4 characters)
*/
public String password;
/**
* A default, no-args constructor, as well as correctly formatted getters and setters, are needed for
* Jackson Objectmapper to work.
*/
public Account(){

}
/**
* When posting a new Account, the id can be generated by the database. In that case, a constructor without
* account_id is needed.
* @param username
* @param password
*/
public Account(String username, String password){
this.username = username;
this.password = password;
}
/**
* Whem retrieving an Account from the database, all fields will be needed. In that case, a constructor with all
* fields is needed.
* @param account_id
* @param username
* @param password
*/
public Account(int account_id, String username, String password) {
this.account_id = account_id;
this.username = username;
this.password = password;
}
/**
* Properly named getters and setters are necessary for Jackson ObjectMapper to work. You may use them as well.
* @return account_id
*/
public int getAccount_id() {
return account_id;
}
/**
* Properly named getters and setters are necessary for Jackson ObjectMapper to work. You may use them as well.
* @param account_id
*/
public void setAccount_id(int account_id) {
this.account_id = account_id;
}
/**
* Properly named getters and setters are necessary for Jackson ObjectMapper to work. You may use them as well.
* @return username
*/
public String getUsername() {
return username;
}
/**
* Properly named getters and setters are necessary for Jackson ObjectMapper to work. You may use them as well.
* @param username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Properly named getters and setters are necessary for Jackson ObjectMapper to work. You may use them as well.
* @return password
*/
public String getPassword() {
return password;
}
/**
* Properly named getters and setters are necessary for Jackson ObjectMapper to work. You may use them as well.
* @param password
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Overriding the default equals() method adds functionality to tell when two objects are identical, allowing
* Assert.assertEquals and List.contains to function.
* @param o the other object.
* @return true if o is equal to this object.
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Account account = (Account) o;
return account_id == account.account_id && username.equals(account.username) && password.equals(account.password);
}
/**
* Overriding the default toString() method allows for easy debugging.
* @return a String representation of this class.
*/
@Override
public String toString() {
return "Account{" +
"account_id=" + account_id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
Loading

0 comments on commit e788847

Please sign in to comment.