diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000000000000000000000000000000000000..4d1ded0118d91ed44f2dc7c7bb680e7327975fa0 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,27 @@ +version: '3.8' + +services: + goservice: + image: graduit-be + env_file: .env + ports: + - "8080:8080" + + nginx: + build: ./nginx + ports: + - "80:80" + - "443:443" + depends_on: + - goservice + volumes: + - ./data/certbot/conf:/etc/letsencrypt + - ./data/certbot/www:/var/www/certbot + command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" + + certbot: + image: certbot/certbot + volumes: + - ./data/certbot/conf:/etc/letsencrypt + - ./data/certbot/www:/var/www/certbot + entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index e4d8efbada9c8fb11ab4fda0d6550af6e4b95107..3760b0c8d2a89a496a5228a15e3a8fde78465ebd 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,19 +1,5 @@ version: "3.8" services: - graduit_server: - build: . - ports: - - 8080:8080 - hostname: graduit_server - env_file: .env - volumes: - - ./:/usr/app - - /usr/app/db-data - restart: always - depends_on: - - graduit_db - - s2_db - s2_db: image: postgres:alpine ports: diff --git a/init-letsencrypt.sh b/init-letsencrypt.sh new file mode 100755 index 0000000000000000000000000000000000000000..6f0c741f9e8425af42f3d30418843e3ec5a70fa8 --- /dev/null +++ b/init-letsencrypt.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +if ! [ -x "$(command -v docker-compose)" ]; then + echo 'Error: docker-compose is not installed.' >&2 + exit 1 +fi + +domains=(s1api.domainbuattesting.my.id) +rsa_key_size=4096 +data_path="./data/certbot" +email="" # Adding a valid address is strongly recommended +staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits + +if [ -d "$data_path" ]; then + read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision + if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then + exit + fi +fi + + +if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then + echo "### Downloading recommended TLS parameters ..." + mkdir -p "$data_path/conf" + curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf" + curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem" + echo +fi + +echo "### Creating dummy certificate for $domains ..." +path="/etc/letsencrypt/live/$domains" +mkdir -p "$data_path/conf/live/$domains" +docker-compose -f docker-compose.prod.yml run --rm --entrypoint "\ + openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 1\ + -keyout '$path/privkey.pem' \ + -out '$path/fullchain.pem' \ + -subj '/CN=localhost'" certbot +echo + + +echo "### Starting nginx ..." +docker-compose -f docker-compose.prod.yml up --force-recreate -d nginx +echo + +echo "### Deleting dummy certificate for $domains ..." +docker-compose -f docker-compose.prod.yml run --rm --entrypoint "\ + rm -Rf /etc/letsencrypt/live/$domains && \ + rm -Rf /etc/letsencrypt/archive/$domains && \ + rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot +echo + + +echo "### Requesting Let's Encrypt certificate for $domains ..." +#Join $domains to -d args +domain_args="" +for domain in "${domains[@]}"; do + domain_args="$domain_args -d $domain" +done + +# Select appropriate email arg +case "$email" in + "") email_arg="--register-unsafely-without-email" ;; + *) email_arg="--email $email" ;; +esac + +# Enable staging mode if needed +if [ $staging != "0" ]; then staging_arg="--staging"; fi + +docker-compose -f docker-compose.prod.yml run --rm --entrypoint "\ + certbot certonly --webroot -w /var/www/certbot \ + $staging_arg \ + $email_arg \ + $domain_args \ + --rsa-key-size $rsa_key_size \ + --agree-tos \ + --force-renewal" certbot +echo + +echo "### Reloading nginx ..." +docker-compose -f docker-compose.prod.yml exec nginx nginx -s reload diff --git a/src/handler/handler.go b/src/handler/handler.go index d9f5c953353ca9d8806914d9b8b1341f08017a6e..19ada8be1289f6ff9d5ad714031abb6a903bb784 100644 --- a/src/handler/handler.go +++ b/src/handler/handler.go @@ -14,6 +14,8 @@ import ( dashboardMahasiswaTransport "gitlab.informatika.org/k-01-11/graduit-be/src/module/dashboard_mahasiswa/transport" dashboardTimTugasConfig "gitlab.informatika.org/k-01-11/graduit-be/src/module/dashboard_tim_tugas/config" dashboardTimTugasTransport "gitlab.informatika.org/k-01-11/graduit-be/src/module/dashboard_tim_tugas/transport" + dashboardTimTAConfig "gitlab.informatika.org/k-01-11/graduit-be/src/module/dashboard_tim_ta/config" + dashboardTimTATransport "gitlab.informatika.org/k-01-11/graduit-be/src/module/dashboard_tim_ta/transport" pendaftaranConfig "gitlab.informatika.org/k-01-11/graduit-be/src/module/pendaftaran/config" pendaftaranTransport "gitlab.informatika.org/k-01-11/graduit-be/src/module/pendaftaran/transport" pendaftaranSidSemConfig "gitlab.informatika.org/k-01-11/graduit-be/src/module/pendaftaran_sidsem/config" @@ -49,6 +51,8 @@ type Service struct { TIMTASchedulingHandler *schedulingTransport.TIMTASchedulingHandler MahasiswaPendaftaranSidSemHandler *pendaftaranSidSemTransport.MahasiswaPendaftaranSidSemHandler TIMTAPendaftaranSidSemHandler *pendaftaranSidSemTransport.TIMTAPendaftaranSidSemHandler + TIMTADashboardTimHandler *dashboardTimTATransport.TIMTADashboardTimHandler + } func MakeHandler() *Service { @@ -118,6 +122,11 @@ func MakeHandler() *Service { DBRead: dbRead, }) + TIMTADashboardHandler := dashboardTimTATransport.NewTIMTADashboardTimHandler(dashboardTimTAConfig.DashboardTimTransportConfig{ + DBWrite: dbWrite, + DBRead: dbRead, + }) + TIMTASchedulingHandlerHandler := schedulingTransport.NewTIMTASchedulingHandler(schedulingConfig.SchedulingTransportConfig{ DBWrite: dbWrite, DBRead: dbRead, @@ -150,5 +159,6 @@ func MakeHandler() *Service { MahasiswaPendaftaranSidSemHandler: MahasiswaPendaftaranSidSemHandler, TIMTAPendaftaranSidSemHandler: TIMTAPendaftaranSidSemHandler, AdminRuanganHandler: AdminRuanganHandler, + TIMTADashboardTimHandler: TIMTADashboardHandler, } } diff --git a/src/handler/server.go b/src/handler/server.go index 0353fb9be7c539da2c75dc3d44b44c5e3bbc5be4..bbefc56b5425682207fe15c3bfb79f4301894352 100644 --- a/src/handler/server.go +++ b/src/handler/server.go @@ -63,6 +63,7 @@ func (s *Service) InitializeRoutes() *echo.Echo { TIMTAGroup.Use(middleware.Validator("S1_TIM_TA")) s.TIMTASchedulingHandler.MountTIMTA(TIMTAGroup) s.TIMTAPendaftaranSidSemHandler.MountTIMTA(TIMTAGroup) + s.TIMTADashboardTimHandler.MountTIMTA(TIMTAGroup) return e } diff --git a/src/module/dashboard_tim_ta/entity/dashboard_tim_ta.go b/src/module/dashboard_tim_ta/entity/dashboard_tim_ta.go index 1fe62afd879a141e6e04d9011fda4c9130548368..c38f71ae3fb147624d3b178541cb4603d163bb8d 100644 --- a/src/module/dashboard_tim_ta/entity/dashboard_tim_ta.go +++ b/src/module/dashboard_tim_ta/entity/dashboard_tim_ta.go @@ -12,3 +12,12 @@ type DataPendaftaran struct { DosenPembimbing string `json:"dosbing"` Status string `json:"status"` } + +type StatusMahasiswa struct { + Id string `json:"id"` + NIM string `json:"nim"` + Nama string `json:"nama"` + PengajuanTopik bool + SeminarProposal bool + Sidang bool +} diff --git a/src/module/dashboard_tim_ta/internal/repository/dashboard_tim_ta.go b/src/module/dashboard_tim_ta/internal/repository/dashboard_tim_ta.go index dd0e75df33a1053aa756ea9230f65182bfbdaeac..a17c999b0cefddc5becde43020c43c75f30d9ed3 100644 --- a/src/module/dashboard_tim_ta/internal/repository/dashboard_tim_ta.go +++ b/src/module/dashboard_tim_ta/internal/repository/dashboard_tim_ta.go @@ -70,3 +70,69 @@ func (repo *DashboardTimRepo) GetDataDashboard(offset, size int) (output []entit return dataMahasiswa, nil } + +func (repo *DashboardTimRepo) GetStatusDashboard(offset, size int) (output []entity.StatusMahasiswa, err error) { + var statusMahasiswa []entity.StatusMahasiswa + var mahasiswa []models.Pengguna + + // Find all users that have role S1_MAHASISWA + result := repo.DBRead.Where("roles @> ?", "{S1_MAHASISWA}").Limit(size).Offset(offset).Find(&mahasiswa) + if result.Error != nil { + return nil, result.Error + } + + for _, mhs := range mahasiswa { + var proposal models.PendaftaranTA + var sidsem models.PendaftaranSidSem + var taStatus, seminarStatus, sidangStatus bool + + // Check status for TA + taResult := repo.DBRead.Where("id_mahasiswa = ?", mhs.ID).First(&proposal) + if taResult.Error != nil { + taStatus = false + } else if proposal.Status != "APPROVED" { + taStatus = false + } else { + taStatus = true + } + + // Check status for Seminar Proposal + seminarResult := repo.DBRead.Where("pendaftaran_ta_id = ? AND tipe = ?", proposal.ID, "Seminar Proposal").First(&sidsem) + if seminarResult.Error != nil { + seminarStatus = false + } else if !sidsem.Ditolak { + seminarStatus = false + } else if sidsem.Ditolak { + seminarStatus = true + } else { + seminarStatus = false + } + + // Check status for Sidang Proposal + sidangResult := repo.DBRead.Where("pendaftaran_ta_id = ? AND tipe = ?", mhs.ID, "Sidang Proposal").First(&sidsem) + if sidangResult.Error != nil { + sidangStatus = false + } else if !sidsem.Ditolak { + sidangStatus = false + } else if sidsem.Ditolak { + sidangStatus = true + } else { + sidangStatus = false + } + + // Create StatusMahasiswa entity + data := entity.StatusMahasiswa{ + Id: mhs.ID, + NIM: mhs.NIM, + Nama: mhs.Nama, + PengajuanTopik: taStatus, + SeminarProposal: seminarStatus, + Sidang: sidangStatus, + } + + // Append to output + statusMahasiswa = append(statusMahasiswa, data) + } + + return statusMahasiswa, nil +} diff --git a/src/module/dashboard_tim_ta/internal/usecase/dashboard_tim_ta.go b/src/module/dashboard_tim_ta/internal/usecase/dashboard_tim_ta.go index d83a54a19b9670f4ec96ee93f47b0af69cd01d07..92c0e1aa7acaa03269646400f8fd6a52259dd1e3 100644 --- a/src/module/dashboard_tim_ta/internal/usecase/dashboard_tim_ta.go +++ b/src/module/dashboard_tim_ta/internal/usecase/dashboard_tim_ta.go @@ -4,6 +4,7 @@ import "gitlab.informatika.org/k-01-11/graduit-be/src/module/dashboard_tim_ta/en type DashboardTimUseCase interface { GetDataMahasiswa(offset, size int) (output []entity.DataPendaftaran, err error) + GetStatusMahasiswa(offset, size int) (output []entity.StatusMahasiswa, err error) } type DashboardTimUc struct { @@ -25,3 +26,13 @@ func (uc *DashboardTimUc) GetDataMahasiswa(offset, size int) (output []entity.Da return listMahasiswa, nil } + +func (uc *DashboardTimUc) GetStatusMahasiswa(offset, size int) (output []entity.StatusMahasiswa, err error) { + listMahasiswa, err := uc.dashboardTimRepo.GetStatusDashboard(offset, size) + + if err != nil { + return listMahasiswa, err + } + + return listMahasiswa, nil +} diff --git a/src/module/dashboard_tim_ta/internal/usecase/repository.go b/src/module/dashboard_tim_ta/internal/usecase/repository.go index 9114e4d92a09b8402175e7aa77de7a570fd29fb5..559e2203aed7c45b9af35c107381c25b1829f98e 100644 --- a/src/module/dashboard_tim_ta/internal/usecase/repository.go +++ b/src/module/dashboard_tim_ta/internal/usecase/repository.go @@ -4,4 +4,5 @@ import "gitlab.informatika.org/k-01-11/graduit-be/src/module/dashboard_tim_ta/en type DashboardTimRepository interface { GetDataDashboard(offset, size int) (output []entity.DataPendaftaran, err error) + GetStatusDashboard(offset, size int) (output []entity.StatusMahasiswa, err error) } diff --git a/src/module/dashboard_tim_ta/transport/admin_handler.go b/src/module/dashboard_tim_ta/transport/timta_handler.go similarity index 63% rename from src/module/dashboard_tim_ta/transport/admin_handler.go rename to src/module/dashboard_tim_ta/transport/timta_handler.go index 1d5f73545c5b24299ebb3b6a95d5b67f811e0e40..cf6983ae87e31e48717eaeac696367c244147673 100644 --- a/src/module/dashboard_tim_ta/transport/admin_handler.go +++ b/src/module/dashboard_tim_ta/transport/timta_handler.go @@ -11,21 +11,22 @@ import ( "gitlab.informatika.org/k-01-11/graduit-be/src/utils" ) -type AdminDashboardTimHandler struct { +type TIMTADashboardTimHandler struct { dashboardTimUseCase usecase.DashboardTimUseCase } -func NewAdminDashboardTimHandler(cfg config.DashboardTimTransportConfig) *AdminDashboardTimHandler { +func NewTIMTADashboardTimHandler(cfg config.DashboardTimTransportConfig) *TIMTADashboardTimHandler { dashboardTimRepository := repository.NewDashboardTimRepository(cfg.DBWrite, cfg.DBRead) dashboardTimUsecase := usecase.NewDashboardTimUsecase(dashboardTimRepository) - return &AdminDashboardTimHandler{ + return &TIMTADashboardTimHandler{ dashboardTimUseCase: dashboardTimUsecase, } } -func (t *AdminDashboardTimHandler) MountAdmin(group *echo.Group) { +func (t *TIMTADashboardTimHandler) MountTIMTA(group *echo.Group) { group.GET("/dashboard-tim", t.GetDataMahasiswa) + group.GET("/dashboard-status", t.GetStatusMahasiswa) } // GetDataMahasiswa retrieves a list of mahasiswa that has already done pendaftaran @@ -39,7 +40,7 @@ func (t *AdminDashboardTimHandler) MountAdmin(group *echo.Group) { // @Param offset query string false "Offset" // @Success 200 {object} []entity.DataPendaftaran "List mahasiswa successfully retrieved" // @Router /dashboard-tim [get] -func (t *AdminDashboardTimHandler) GetDataMahasiswa(c echo.Context) error { +func (t *TIMTADashboardTimHandler) GetDataMahasiswa(c echo.Context) error { sizeStr := c.QueryParam("limit") offsetStr := c.QueryParam("offset") @@ -63,3 +64,28 @@ func (t *AdminDashboardTimHandler) GetDataMahasiswa(c echo.Context) error { return c.JSON(http.StatusOK, utils.ResponseDetailOutput(true, http.StatusOK, "List mahasiswa successfully retreived", listMahasiswa)) } + +func (t *TIMTADashboardTimHandler) GetStatusMahasiswa(c echo.Context) error { + sizeStr := c.QueryParam("limit") + offsetStr := c.QueryParam("offset") + + size, err := strconv.Atoi(sizeStr) + if err != nil { + // Handle error, maybe return an error response + size = 10 + } + + offset, err := strconv.Atoi(offsetStr) + if err != nil { + // Handle error, maybe return an error response + offset = 0 + } + + listMahasiswa, err := t.dashboardTimUseCase.GetStatusMahasiswa(offset, size) + if err != nil { + return c.JSON(http.StatusBadRequest, utils.ResponseDetailOutput(false, http.StatusBadRequest, err.Error(), nil)) + } + + return c.JSON(http.StatusOK, utils.ResponseDetailOutput(true, http.StatusOK, "List Status mahasiswa successfully retreived", listMahasiswa)) + +} \ No newline at end of file