Skip to content

Commit

Permalink
feat: List supported languages (#122)
Browse files Browse the repository at this point in the history
* refactor(db): Create  `archives` table

* chore(lang): Create `languages` package

* feat(db): Insert Java to the `languages` table

* feat(lang): Add endpoint to list supported languages

* test(lang): Add test to ensure languages are listed correctly
  • Loading branch information
PedroChaparro authored Dec 28, 2023
1 parent 5983288 commit e7d7539
Show file tree
Hide file tree
Showing 16 changed files with 302 additions and 18 deletions.
37 changes: 37 additions & 0 deletions __tests__/integration/languages_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package integration

import (
"net/http"
"testing"

"github.com/stretchr/testify/require"
)

func TestListSupportedLanguages(t *testing.T) {
c := require.New(t)

// Login as an student
w, r := PrepareRequest("POST", "/api/v1/session/login", map[string]interface{}{
"email": registeredStudentEmail,
"password": registeredStudentPass,
})
router.ServeHTTP(w, r)
cookie := w.Result().Cookies()[0]

// Get the supported languages
response, statusCode := GetSupportedLanguages(cookie)
c.Equal(http.StatusOK, statusCode)

// Check the response
languages := response["languages"].([]interface{})
c.Greater(len(languages), 0)

// Get all the languages names
var languagesNames []string
for _, language := range languages {
languagesNames = append(languagesNames, language.(map[string]interface{})["name"].(string))
}

// Check if the supported languages are included
c.Contains(languagesNames, "Java")
}
10 changes: 10 additions & 0 deletions __tests__/integration/languages_utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package integration

import "net/http"

func GetSupportedLanguages(cookie *http.Cookie) (response map[string]interface{}, statusCode int) {
w, r := PrepareRequest("GET", "/api/v1/languages", nil)
r.AddCookie(cookie)
router.ServeHTTP(w, r)
return ParseJsonResponse(w.Body), w.Code
}
11 changes: 11 additions & 0 deletions docs/bruno/languages/list-languages.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
meta {
name: list-languages
type: http
seq: 1
}

get {
url: {{BASE_URL}}/languages
body: none
auth: none
}
2 changes: 2 additions & 0 deletions sql/migrations/20230920232901_init.down.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ DROP VIEW IF EXISTS objectives_owners;
DROP VIEW IF EXISTS criteria_owners;

-- ## Tables
DROP TABLE IF EXISTS archives;

DROP TABLE IF EXISTS grade_has_criteria;

DROP TABLE IF EXISTS grades;
Expand Down
70 changes: 53 additions & 17 deletions sql/migrations/20230920232901_init.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ CREATE TABLE IF NOT EXISTS rubrics (
CREATE TABLE IF NOT EXISTS objectives (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"rubric_id" UUID NOT NULL REFERENCES rubrics(id),
"description" VARCHAR(510) NOT NULL,
"description" VARCHAR(510) NOT NULL,
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

Expand All @@ -69,10 +69,12 @@ CREATE TABLE IF NOT EXISTS criteria (
CREATE TABLE IF NOT EXISTS laboratories (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"course_id" UUID NOT NULL REFERENCES courses(id),
"rubric_id" UUID DEFAULT NULL REFERENCES rubrics(id) ON DELETE SET DEFAULT,
"name" VARCHAR(255) NOT NULL,
"opening_date" TIMESTAMP NOT NULL,
"due_date" TIMESTAMP NOT NULL
"rubric_id" UUID DEFAULT NULL REFERENCES rubrics(id) ON DELETE
SET
DEFAULT,
"name" VARCHAR(255) NOT NULL,
"opening_date" TIMESTAMP NOT NULL,
"due_date" TIMESTAMP NOT NULL
);

CREATE TABLE IF NOT EXISTS blocks_index (
Expand All @@ -88,17 +90,22 @@ CREATE TABLE IF NOT EXISTS markdown_blocks (
"content" TEXT NOT NULL DEFAULT ''
);

CREATE TABLE IF NOT EXISTS archives (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"file_id" UUID NOT NULL UNIQUE
);

CREATE TABLE IF NOT EXISTS languages (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"name" VARCHAR(32) NOT NULL UNIQUE,
"base_archive" BYTEA NOT NULL
"template_archive_id" UUID NOT NULL UNIQUE REFERENCES archives(id),
"name" VARCHAR(32) NOT NULL UNIQUE
);

CREATE TABLE IF NOT EXISTS test_blocks (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"laboratory_id" UUID NOT NULL REFERENCES laboratories(id),
"language_id" UUID NOT NULL REFERENCES languages(id),
"tests_archive_id" BYTEA NOT NULL,
"test_archive_id" UUID NOT NULL UNIQUE REFERENCES archives(id),
"laboratory_id" UUID NOT NULL REFERENCES laboratories(id),
"block_index_id" UUID NOT NULL REFERENCES blocks_index(id) ON DELETE CASCADE,
"name" VARCHAR(255) NOT NULL
);
Expand All @@ -107,12 +114,11 @@ CREATE TABLE IF NOT EXISTS submissions (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"test_id" UUID NOT NULL REFERENCES test_blocks(id),
"student_id" UUID NOT NULL REFERENCES users(id),
"archive" BYTEA NOT NULL,
"archive_id" UUID NOT NULL UNIQUE REFERENCES archives(id),
"passing" BOOLEAN NOT NULL DEFAULT FALSE,
"status" SUBMISSION_STATUS NOT NULL DEFAULT 'pending',
"stdout" TEXT NOT NULL DEFAULT '',
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
"submitted_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS grades (
Expand Down Expand Up @@ -141,12 +147,13 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_blocks_index ON blocks_index(laboratory_id

-- ### Search indexes
CREATE INDEX IF NOT EXISTS idx_users_role ON users(role);

CREATE INDEX IF NOT EXISTS idx_users_lower_fullName ON users(LOWER(full_name));

-- ## Views
--- ### Users
CREATE
OR REPLACE VIEW users_with_creator AS
OR REPLACE VIEW users_with_creator AS
SELECT
users.id,
users.role,
Expand Down Expand Up @@ -230,10 +237,10 @@ BEGIN
END $$
;

CREATE OR REPLACE TRIGGER set_created_by
BEFORE INSERT ON users
FOR EACH ROW
EXECUTE PROCEDURE update_created_by();
CREATE
OR REPLACE TRIGGER set_created_by BEFORE
INSERT
ON users FOR EACH ROW EXECUTE PROCEDURE update_created_by();

-- ## Data
-- ### Colors
Expand All @@ -247,6 +254,35 @@ VALUES
('#fbbf24'),
('#f472b6');

-- ### Languages
DO $$

DECLARE
JAVA_FILESYSTEM_ARCHIVE_UUID UUID;
JAVA_DB_ARCHIVE_UUID UUID;

BEGIN
JAVA_FILESYSTEM_ARCHIVE_UUID := '487034c9-441c-4fb9-b0f3-8f4dd6176532';

INSERT INTO
archives (file_id)
VALUES
(JAVA_FILESYSTEM_ARCHIVE_UUID)
RETURNING
id
INTO
JAVA_DB_ARCHIVE_UUID;

INSERT INTO
languages (name, template_archive_id)
VALUES
(
'Java',
JAVA_DB_ARCHIVE_UUID
);

END $$;

-- ### Admin user (To be used in development)
INSERT INTO
users (
Expand Down
2 changes: 2 additions & 0 deletions src/config/infrastructure/http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
blocks_http "github.com/UPB-Code-Labs/main-api/src/blocks/infrastructure/http"
courses_http "github.com/UPB-Code-Labs/main-api/src/courses/infrastructure/http"
laboratories_http "github.com/UPB-Code-Labs/main-api/src/laboratories/infrastructure/http"
languages_http "github.com/UPB-Code-Labs/main-api/src/languages/infrastructure/http"
rubrics_http "github.com/UPB-Code-Labs/main-api/src/rubrics/infrastructure/http"
session_http "github.com/UPB-Code-Labs/main-api/src/session/infrastructure/http"
shared_infra "github.com/UPB-Code-Labs/main-api/src/shared/infrastructure"
Expand All @@ -19,6 +20,7 @@ var routesGroups = []func(*gin.RouterGroup){
courses_http.StartCoursesRoutes,
rubrics_http.StartRubricsRoutes,
laboratories_http.StartLaboratoriesRoutes,
languages_http.StartLanguagesRoutes,
}

func InstanceHttpServer() (r *gin.Engine) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (repository *LaboratoriesPostgresRepository) getTestBlocks(laboratoryUUID s
defer cancel()

query := `
SELECT tb.id, tb.language_id, tb.tests_archive_id, tb.name, bi.block_position
SELECT tb.id, tb.language_id, tb.test_archive_id, tb.name, bi.block_position
FROM test_blocks tb
RIGHT JOIN blocks_index bi ON tb.block_index_id = bi.id
WHERE tb.laboratory_id = $1
Expand Down
18 changes: 18 additions & 0 deletions src/languages/application/usec_cases.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package application

import (
"github.com/UPB-Code-Labs/main-api/src/languages/domain/definitions"
"github.com/UPB-Code-Labs/main-api/src/languages/domain/entities"
)

type LanguageUseCases struct {
LanguageRepository definitions.LanguagesRepository
}

func (useCases *LanguageUseCases) GetLanguages() ([]*entities.Language, error) {
return useCases.LanguageRepository.GetAll()
}

func (useCases *LanguageUseCases) GetLanguageByUUID(uuid string) (*entities.Language, error) {
return useCases.LanguageRepository.GetByUUID(uuid)
}
8 changes: 8 additions & 0 deletions src/languages/domain/definitions/languages_repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package definitions

import "github.com/UPB-Code-Labs/main-api/src/languages/domain/entities"

type LanguagesRepository interface {
GetAll() (languages []*entities.Language, err error)
GetByUUID(uuid string) (language *entities.Language, err error)
}
Empty file.
7 changes: 7 additions & 0 deletions src/languages/domain/entities/language.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package entities

type Language struct {
UUID string `json:"uuid"`
TemplateArchiveUUID string `json:"-"`
Name string `json:"name"`
}
13 changes: 13 additions & 0 deletions src/languages/domain/errors/languages_errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package errors

import "net/http"

type LangNotFoundError struct{}

func (err *LangNotFoundError) Error() string {
return "Language not found"
}

func (err *LangNotFoundError) StatusCode() int {
return http.StatusNotFound
}
28 changes: 28 additions & 0 deletions src/languages/infrastructure/http/http_controllers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package http

import (
"net/http"

"github.com/UPB-Code-Labs/main-api/src/languages/application"
"github.com/gin-gonic/gin"
)

type LanguagesController struct {
UseCases *application.LanguageUseCases
}

func (controller *LanguagesController) HandleGetLanguages(c *gin.Context) {
languages, err := controller.UseCases.GetLanguages()
if err != nil {
c.Error(err)
return
}

c.JSON(http.StatusOK, gin.H{
"languages": languages,
})
}

func (controller *LanguagesController) HandleDownloadLanguageTemplate(c *gin.Context) {
c.Status(http.StatusNotImplemented)
}
33 changes: 33 additions & 0 deletions src/languages/infrastructure/http/http_routes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package http

import (
"github.com/UPB-Code-Labs/main-api/src/languages/application"
"github.com/UPB-Code-Labs/main-api/src/languages/infrastructure/implementations"
shared_infrastructure "github.com/UPB-Code-Labs/main-api/src/shared/infrastructure"
"github.com/gin-gonic/gin"
)

func StartLanguagesRoutes(g *gin.RouterGroup) {
langGroup := g.Group("/languages")

useCases := application.LanguageUseCases{
LanguageRepository: implementations.GetLanguagesRepositoryInstance(),
}

controllers := LanguagesController{
UseCases: &useCases,
}

langGroup.GET(
"",
shared_infrastructure.WithAuthenticationMiddleware(),
shared_infrastructure.WithAuthorizationMiddleware([]string{"teacher", "student"}),
controllers.HandleGetLanguages,
)
langGroup.GET(
"/:language_uuid/template",
shared_infrastructure.WithAuthenticationMiddleware(),
shared_infrastructure.WithAuthorizationMiddleware([]string{"teacher", "student"}),
controllers.HandleDownloadLanguageTemplate,
)
}
Loading

0 comments on commit e7d7539

Please sign in to comment.