Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/java_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
matrix:
# Add any future services relative paths from . here
service: [user]
service: [user, matching]

steps:

Expand All @@ -41,7 +41,7 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
name: junit-test-results
name: ${{ matrix.service }}-junit-test-results
path: |
server/${{ matrix.service }}/build/test-results
server/${{ matrix.service }}/build/reports/tests
Expand Down
89 changes: 89 additions & 0 deletions deployment/debug/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# This file is used to deploy the microservices using Docker Compose.
# It defines the services, their images, build context, and ports.

services:
gateway-service:
build: ../../server/gateway
container_name: meetatmensa-gateway
ports:
- "8080:80"
depends_on:
- matching-service
- user-service
- genai-service
networks:
- backend

matching-service:
build: ../../server/matching
container_name: meetatmensa-matching
expose:
- "80"
ports:
- "8081:80"
depends_on:
- match-database
networks:
- backend

user-service:
build: ../../server/user
container_name: meetatmensa-user
expose:
- "80"
ports:
- "8082:80"
depends_on:
- user-database
networks:
- backend

genai-service:
build: ../../server/genai
container_name: meetatmensa-genai
expose:
- "80"
ports:
- "8083:80"
networks:
- backend

client-service:
build: ../../client
container_name: meetatmensa-client
ports:
- "80:80"

match-database:
build: ../../server/database/matchdb
container_name: meetatmensa-matchdb
# TODO: Implement password passed via secret
environment:
- MYSQL_ROOT_PASSWORD=root
volumes:
- matchdb_data:/var/lib/mysql
expose:
- "3306"
networks:
- backend

user-database:
build: ../../server/database/userdb
container_name: meetatmensa-userdb
# TODO: Implement password passed via secret
environment:
- MYSQL_ROOT_PASSWORD=root
volumes:
- userdb_data:/var/lib/mysql
expose:
- "3306"
networks:
- backend

networks:
backend:
driver: bridge

volumes:
matchdb_data:
userdb_data:
3 changes: 3 additions & 0 deletions server/matching/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.testcontainers:testcontainers:1.21.3'
testImplementation 'org.testcontainers:mysql:1.21.3'
testImplementation "org.testcontainers:junit-jupiter:1.21.3"
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
runtimeOnly 'com.mysql:mysql-connector-j:9.3.0'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
import org.openapitools.client.model.User;

import org.openapitools.model.UserCollection;
import org.springframework.stereotype.Service;

import meet_at_mensa.matching.exception.RestException;

@Service
public class UserClient {

private ApiClient defaultClient;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package meet_at_mensa.matching.service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.openapitools.model.Group;
import org.openapitools.model.Location;
import org.openapitools.model.MatchStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import meet_at_mensa.matching.exception.GroupNotFoundException;
import meet_at_mensa.matching.exception.MatchNotFoundException;
import meet_at_mensa.matching.model.GroupEntity;
import meet_at_mensa.matching.model.MatchEntity;
import meet_at_mensa.matching.repository.GroupRepository;
import meet_at_mensa.matching.repository.MatchRepository;

@Service
public class GroupService {
Expand All @@ -20,10 +26,10 @@ public class GroupService {
private GroupRepository groupRepository;

@Autowired
private ConversationStarterService conversationStarterService;
private MatchRepository matchRepository;

@Autowired
private MatchService matchService;
private ConversationStarterService conversationStarterService;

/**
* Searches the database for a group with this groupID
Expand All @@ -43,7 +49,7 @@ public Group getGroup(UUID groupID) {
groupEntity.getDate(), // date
groupEntity.getTimeslot(), // timeslot
groupEntity.getLocation(), // Location (enum)
matchService.getMatchStatus(groupID), // List<MatchStatus>
getGroupStatus(groupID), // List<MatchStatus>
conversationStarterService.getPrompts(groupID) // ConversationStarterCollection
);

Expand Down Expand Up @@ -74,4 +80,40 @@ protected UUID registerGroup(LocalDate date, Integer timeslot, Location location
return group.getGroupID();
}


/**
* Retieves the match status for all users in a group
*
*
* @param groupID UUID of the group
* @return List<MatchStatus> objects representing each users' status
* @throws MatchNotFoundException if no user with id {userID} is found
*/
private List<MatchStatus> getGroupStatus(UUID groupID){

// get all matches in the system for a given group ID
Iterable<MatchEntity> matchEntities = matchRepository.findByGroupID(groupID);

// if list is empty, throw exception
if (!matchEntities.iterator().hasNext()) {
throw new MatchNotFoundException();
}

// create blank matchstatus list
List<MatchStatus> groupStatus = new ArrayList<MatchStatus>();

for (MatchEntity matchEntity : matchEntities) {

// create a match Status object for a single user
MatchStatus matchStatus = new MatchStatus(matchEntity.getUserID(), matchEntity.getInviteStatus());

// add it to the list
groupStatus.add(matchStatus);

}

// return the list
return groupStatus;

}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package meet_at_mensa.matching.service;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.openapitools.model.InviteStatus;
import org.openapitools.model.Match;
import org.openapitools.model.MatchCollection;
import org.openapitools.model.MatchStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

Expand All @@ -27,42 +24,6 @@ public class MatchService {
@Autowired
private GroupService groupService;


/**
* Retieves the match status for all users in a group
*
*
* @param groupID UUID of the group
* @return List<MatchStatus> objects representing each users' status
* @throws MatchNotFoundException if no user with id {userID} is found
*/
public List<MatchStatus> getMatchStatus(UUID groupID) {

// get all matches in the system for a given group ID
Iterable<MatchEntity> matchEntities = matchRepository.findByGroupID(groupID);

// if list is empty, throw exception
if (!matchEntities.iterator().hasNext()) {
throw new MatchNotFoundException();
}

// create blank matchstatus list
List<MatchStatus> groupStatus = new ArrayList<MatchStatus>();

for (MatchEntity matchEntity : matchEntities) {

// create a match Status object for a single user
MatchStatus matchStatus = new MatchStatus(matchEntity.getUserID(), matchEntity.getInviteStatus());

// add it to the list
groupStatus.add(matchStatus);

}

// return the list
return groupStatus;
}

/**
* Retieves a specific match by it's matchID
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,31 @@

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

@SpringBootTest
// MatchingApplicationTests is a test class for the matching application
@Testcontainers
// MatchingpplicationTests is a test class for the matching application
class MatchingApplicationTests {

@Container
static MySQLContainer<?> matchdb = new MySQLContainer<>("mysql:8.0")
.withDatabaseName("matchdb")
.withInitScript("init_matchdb_test.sql")
.withUsername("root")
.withPassword("root");

@DynamicPropertySource
static void overrideProps(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", matchdb::getJdbcUrl);
registry.add("spring.datasource.username", matchdb::getUsername);
registry.add("spring.datasource.password", matchdb::getPassword);
}

@Test
void contextLoads() {
}
Expand Down
67 changes: 67 additions & 0 deletions server/matching/src/test/resources/init_matchdb_test.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
-- matches table
-- which user has been matched with which group
-- match_id: UUID of the match, primary key
-- user_id: UUID of the matched user
-- group_id: UUID of group the user has been matched to
-- invite_status: Has the user RSVP'd?
CREATE TABLE IF NOT EXISTS `matches` (
match_id VARBINARY(16) PRIMARY KEY,
user_id VARBINARY(16) NOT NULL,
group_id VARBINARY(16) NOT NULL,
invite_status VARCHAR(255) NOT NULL
);

-- groups table
-- information about groups
-- group_id: UUID of the group
-- meet_date: date a group is set to meet
-- meet_timeslot: time a group is set to meet, encoded as Integer
-- meet_location: mensa a group is set to meet at
CREATE TABLE IF NOT EXISTS `groups` (
group_id VARBINARY(16) PRIMARY KEY,
meet_date DATE NOT NULL,
meet_timeslot INT NOT NULL,
meet_location VARCHAR(255) NOT NULL
);

-- prompts table
-- contains conversation starters
-- prompt_id: UUID of the prompt
-- group_id: UUID of the group this conversation starter prompt belongs to
-- prompt: prompt itself
CREATE TABLE IF NOT EXISTS `prompts` (
prompt_id VARBINARY(16) PRIMARY KEY,
group_id VARBINARY(16) NOT NULL,
prompt VARCHAR(1023) NOT NULL
);

-- match requests table
-- individual match requests
-- request_id: UUID of the request, primary key
-- user_id: UUID of user making the request
-- group_id: UUID of the group the user was matched to. Null if Unmatched
-- request_date: date the user would like to be matched
-- degree_pref: does user prefer matches with same degree?
-- age_pref: does user prefer matches with same age?
-- gender_pref: does user prefer matches with same gender?
CREATE TABLE IF NOT EXISTS `match_requests` (
request_id VARBINARY(16) PRIMARY KEY,
user_id VARBINARY(16) NOT NULL,
request_date DATE NOT NULL,
request_location VARCHAR(255) NOT NULL,
degree_pref BIT NOT NULL,
age_pref BIT NOT NULL,
gender_pref BIT NOT NULL,
request_status VARCHAR(255) NOT NULL
);

-- match timeslot table
-- What time-slots has a user selected in their requests
-- timeslot_id: UUID primary key (Unique)
-- request_id: UUID of the corresponding request
-- time_slot time slot (encoded as integer)
CREATE TABLE IF NOT EXISTS `match_timeslots` (
timeslot_id VARBINARY(16) PRIMARY KEY,
request_id VARBINARY(16) NOT NULL,
request_timeslot INT NOT NULL
);