project init

This commit is contained in:
areeqakbr 2025-02-13 13:46:06 +07:00
commit b79701e87c
45 changed files with 1862 additions and 0 deletions

45
.gitignore vendored Normal file
View File

@ -0,0 +1,45 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Output of the go coverage tool
*.out
# Temporary files
*.tmp
*.temp
# Build directories
_build/
_builds/
bin/
out/
# Vendor directory
vendor/
# Go modules
go.sum
# IDE and editor files
.vscode/
.idea/
*.swp
*.swo
*.DS_Store
# Logs
*.log
# Dependency directories
Godeps/
node_modules/
# Environment variables
.env
# Coverage files
coverage.out

89
config/config.go Normal file
View File

@ -0,0 +1,89 @@
package config
import (
"errors"
"github.com/joho/godotenv"
"os"
)
type DbConfig struct {
DBUser string
DBPass string
DBHost string
DBPort string
DBName string
}
type LoginConfig struct {
LoginAPI string
AuthMeAPI string
LogoutAPI string
}
type TokenConfig struct {
PassiveAssetIssuer string
JwtSignatureKey []byte
}
type ApiConfig struct {
ApiPort string
}
type TokenApi struct {
TokenApiKey string
}
type Config struct {
DbConfig
TokenConfig
TokenApi
ApiConfig
LoginConfig
}
func (c *Config) readConfig() error {
if err := godotenv.Load(); err != nil {
return errors.New("failed to load environment variables")
}
c.DbConfig = DbConfig{
DBHost: os.Getenv("DB_HOST"),
DBPort: os.Getenv("DB_PORT"),
DBName: os.Getenv("DB_NAME"),
DBUser: os.Getenv("DB_USER"),
DBPass: os.Getenv("DB_PASSWORD"),
}
c.ApiConfig = ApiConfig{
ApiPort: os.Getenv("API_PORT"),
}
c.TokenConfig = TokenConfig{
PassiveAssetIssuer: os.Getenv("PASSIVE_ASSET_ISSUER"),
JwtSignatureKey: []byte(os.Getenv("TOKEN_KEY")),
}
c.TokenApi = TokenApi{
TokenApiKey: os.Getenv("TOKEN_API_KEY"),
}
c.LoginConfig = LoginConfig{
LoginAPI: os.Getenv("API_LOGIN_URL"),
AuthMeAPI: os.Getenv("API_ME_URL"),
LogoutAPI: os.Getenv("API_LOGOUT_URL"),
}
if c.ApiConfig.ApiPort == "" {
return errors.New("failed to read environment variables")
}
return nil
}
func NewConfig() (*Config, error) {
config := &Config{}
err := config.readConfig()
if err != nil {
return nil, err
}
return config, nil
}

View File

@ -0,0 +1,62 @@
package controller
import (
"net/http"
"users_management/m/model/dto/req"
"users_management/m/usecase"
"users_management/m/utils/common"
"github.com/gin-gonic/gin"
)
type BackboneController struct {
bu usecase.BackboneUseCase
rg *gin.RouterGroup
}
func (bc *BackboneController) Route() {
rg := bc.rg.Group("/backbone")
rg.GET("", bc.GetBackbone())
rg.POST("", bc.CreateBackbone())
}
func NewBackboneController(bu usecase.BackboneUseCase, rg *gin.RouterGroup) *BackboneController {
return &BackboneController{
bu: bu,
rg: rg,
}
}
func (bc *BackboneController) GetBackbone() gin.HandlerFunc {
return func(c *gin.Context) {
backbones, err := bc.bu.GetAllBackbone()
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Success", backbones)
}
}
func (bc *BackboneController) CreateBackbone() gin.HandlerFunc {
return func(c *gin.Context) {
var backboneDTO req.BackboneDTO
err := c.ShouldBindJSON(&backboneDTO)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
err = bc.bu.CreateBackbone(backboneDTO)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Backbone has been created", nil)
}
}

View File

@ -0,0 +1,62 @@
package controller
import (
"net/http"
"users_management/m/model/dto/req"
"users_management/m/usecase"
"users_management/m/utils/common"
"github.com/gin-gonic/gin"
)
type DevicePortController struct {
du usecase.DevicePortUseCase
rg *gin.RouterGroup
}
func (dc *DevicePortController) Route() {
rg := dc.rg.Group("/device-port")
rg.GET("", dc.GetDevicePort())
rg.POST("", dc.CreateDevicePort())
}
func NewDevicePortController(du usecase.DevicePortUseCase, rg *gin.RouterGroup) *DevicePortController {
return &DevicePortController{
du: du,
rg: rg,
}
}
func (dc *DevicePortController) GetDevicePort() gin.HandlerFunc {
return func(c *gin.Context) {
devicePorts, err := dc.du.GetAllDevicePort()
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Success", devicePorts)
}
}
func (dc *DevicePortController) CreateDevicePort() gin.HandlerFunc {
return func(c *gin.Context) {
var devicePortDTO req.DevicePort
err := c.ShouldBindJSON(&devicePortDTO)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
err = dc.du.CreateDevicePort(devicePortDTO)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Device Port has been created", nil)
}
}

View File

@ -0,0 +1,62 @@
package controller
import (
"net/http"
"users_management/m/model/dto/req"
"users_management/m/usecase"
"users_management/m/utils/common"
"github.com/gin-gonic/gin"
)
type DeviceController struct {
du usecase.DeviceUseCase
rg *gin.RouterGroup
}
func (dc *DeviceController) Route() {
rg := dc.rg.Group("/devices")
rg.POST("", dc.CreateDevice())
rg.GET("", dc.GetAllDevices())
}
func NewDeviceController(du usecase.DeviceUseCase, rg *gin.RouterGroup) *DeviceController {
return &DeviceController{
du: du,
rg: rg,
}
}
func (dc *DeviceController) CreateDevice() gin.HandlerFunc {
return func(c *gin.Context) {
var deviceDTO req.DeviceDTO
err := c.ShouldBindJSON(&deviceDTO)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
err = dc.du.CreateDevice(deviceDTO)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Device has been created", nil)
}
}
func (dc *DeviceController) GetAllDevices() gin.HandlerFunc {
return func(c *gin.Context) {
devices, err := dc.du.GetAllDevices()
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Success", devices)
}
}

View File

@ -0,0 +1,62 @@
package controller
import (
"net/http"
"users_management/m/model/dto/req"
"users_management/m/usecase"
"users_management/m/utils/common"
"github.com/gin-gonic/gin"
)
type FishboneController struct {
fu usecase.FishboneUseCase
rg *gin.RouterGroup
}
func (fc *FishboneController) Route() {
rg := fc.rg.Group("/fishbone")
rg.GET("", fc.GetFishbone())
rg.POST("", fc.CreateFishbone())
}
func NewFishboneController(fu usecase.FishboneUseCase, rg *gin.RouterGroup) *FishboneController {
return &FishboneController{
fu: fu,
rg: rg,
}
}
func (fc *FishboneController) GetFishbone() gin.HandlerFunc {
return func(c *gin.Context) {
fishbones, err := fc.fu.GetAllFishbone()
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Success", fishbones)
}
}
func (fc *FishboneController) CreateFishbone() gin.HandlerFunc {
return func(c *gin.Context) {
var fishboneDTO req.FishboneDTO
err := c.ShouldBindJSON(&fishboneDTO)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
err = fc.fu.CreateFishbone(fishboneDTO)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Fishbone has been created", nil)
}
}

View File

@ -0,0 +1,62 @@
package controller
import (
"net/http"
"users_management/m/model/dto/req"
"users_management/m/usecase"
"users_management/m/utils/common"
"github.com/gin-gonic/gin"
)
type TowerController struct {
tu usecase.TowerUseCase
rg *gin.RouterGroup
}
func (tc *TowerController) Route() {
rg := tc.rg.Group("/tower")
rg.GET("", tc.GetTower())
rg.POST("", tc.CreateTower())
}
func NewTowerController(tu usecase.TowerUseCase, rg *gin.RouterGroup) *TowerController {
return &TowerController{
tu: tu,
rg: rg,
}
}
func (tc *TowerController) GetTower() gin.HandlerFunc {
return func(c *gin.Context) {
towers, err := tc.tu.GetAll()
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Success", towers)
}
}
func (tc *TowerController) CreateTower() gin.HandlerFunc {
return func(c *gin.Context) {
var towerDTO req.TowerDTO
err := c.ShouldBindJSON(&towerDTO)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
err = tc.tu.Post(towerDTO)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Tower has been created", nil)
}
}

View File

@ -0,0 +1,67 @@
package controller
import (
"net/http"
"users_management/m/model/dto"
"users_management/m/usecase"
"users_management/m/utils/common"
"github.com/gin-gonic/gin"
)
type UsersController struct {
uc usecase.UsersUsecase
ac usecase.AuthUsecase
rg *gin.RouterGroup
}
func (uc *UsersController) Route() {
rg:= uc.rg.Group("/users")
rg.POST("/login", uc.Login())
rg.POST("/logout", uc.Logout())
}
func NewUsersController(uc usecase.UsersUsecase, ac usecase.AuthUsecase,rg *gin.RouterGroup) *UsersController {
return &UsersController{
uc: uc,
ac: ac,
rg: rg,
}
}
func (uc *UsersController) Login() gin.HandlerFunc {
return func(c *gin.Context) {
var login dto.UserLoginDTO
err := c.ShouldBindJSON(&login)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
token, err := uc.ac.Login(login)
if err != nil {
common.ErrorResponses(c, http.StatusUnauthorized, err.Error())
return
}
common.SingleResponses(c, "Login success", gin.H{"token": token})
}
}
func (uc *UsersController) Logout() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
err := uc.ac.Logout(token)
if err != nil {
common.ErrorResponses(c, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(c, "Logout success", nil)
}
}

58
delivery/server.go Normal file
View File

@ -0,0 +1,58 @@
package delivery
import (
"fmt"
"users_management/m/config"
"users_management/m/delivery/controller"
"users_management/m/manager"
"users_management/m/utils/common"
"github.com/gin-gonic/gin"
)
type Server struct {
ucManager manager.UsecaseManager
engine *gin.Engine
host string
}
func NewServer() *Server {
cfg, err := config.NewConfig()
if err != nil {
panic(err)
}
infraManager, err := manager.NewInfraManager(cfg)
if err != nil {
panic(err)
}
repoManager := manager.NewRepositoryManager(infraManager)
ucManager := manager.NewUsecaseManager(repoManager, cfg)
engine := gin.Default()
engine.Use(common.LoggingToFile())
host := fmt.Sprintf(":%s", cfg.ApiPort)
return &Server{
ucManager: ucManager,
engine: engine,
host: host,
}
}
func (s *Server) setupController() {
rg := s.engine.Group("/api/v1")
controller.NewUsersController(s.ucManager.NewUserUsecase(), s.ucManager.NewAuthUsecase(),rg).Route()
controller.NewDeviceController(s.ucManager.NewDeviceUsecase(), rg).Route()
controller.NewBackboneController(s.ucManager.NewBackboneUsecase(), rg).Route()
controller.NewFishboneController(s.ucManager.NewFishboneUsecase(), rg).Route()
controller.NewTowerController(s.ucManager.NewTowerUsecase(), rg).Route()
controller.NewDevicePortController(s.ucManager.NewDevicePortUsecase(), rg).Route()
}
func (s *Server) Run() {
s.setupController()
if err := s.engine.Run(s.host); err != nil {
panic(err)
}
}

48
go.mod Normal file
View File

@ -0,0 +1,48 @@
module users_management/m
go 1.23.1
require (
github.com/gin-gonic/gin v1.10.0
github.com/go-playground/validator/v10 v10.24.0
github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
gorm.io/driver/postgres v1.5.11
gorm.io/gorm v1.25.12
)
require (
github.com/bytedance/sonic v1.12.8 // indirect
github.com/bytedance/sonic/loader v0.2.3 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v1.0.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.14.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

7
main.go Normal file
View File

@ -0,0 +1,7 @@
package main
import "users_management/m/delivery"
func main() {
delivery.NewServer().Run()
}

44
manager/infra_manager.go Normal file
View File

@ -0,0 +1,44 @@
package manager
import (
"fmt"
"users_management/m/config"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type InfraManager interface {
Conn() *gorm.DB
}
type infraManager struct {
db *gorm.DB
cfg *config.Config
}
func (im *infraManager) openConn() error {
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Shanghai",
im.cfg.DBHost, im.cfg.DBUser, im.cfg.DBPass, im.cfg.DBName, im.cfg.DBPort)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
return err
}
im.db = db
return nil
}
func NewInfraManager(cfg *config.Config) (InfraManager, error) {
im := &infraManager{
cfg: cfg,
}
err := im.openConn()
if err != nil {
panic(err)
}
return im, nil
}
func (im *infraManager) Conn() *gorm.DB {
return im.db
}

View File

@ -0,0 +1,47 @@
package manager
import "users_management/m/repository"
type RepositoryManager interface {
NewUserRepository() repository.UsersRepo
NewDeviceRepository() repository.DevicesRepo
NewBackboneRepository() repository.BackboneRepo
NewFishboneRepository() repository.FishboneRepo
NewTowerRepository() repository.TowerRepo
NewDevicePortRepository() repository.DevicePortRepo
}
type repositoryManager struct {
infra InfraManager
}
func NewRepositoryManager(infra InfraManager) RepositoryManager {
return &repositoryManager{
infra: infra,
}
}
func (rm *repositoryManager) NewUserRepository() repository.UsersRepo {
return repository.NewUsersRepo(rm.infra.Conn())
}
func (rm *repositoryManager) NewDeviceRepository() repository.DevicesRepo {
return repository.NewDevicesRepo(rm.infra.Conn())
}
func (rm *repositoryManager) NewBackboneRepository() repository.BackboneRepo {
return repository.NewBackboneRepo(rm.infra.Conn())
}
func (rm *repositoryManager) NewFishboneRepository() repository.FishboneRepo {
return repository.NewFishboneRepo(rm.infra.Conn())
}
func (rm *repositoryManager) NewTowerRepository() repository.TowerRepo {
return repository.NewTowerRepo(rm.infra.Conn())
}
func (rm *repositoryManager) NewDevicePortRepository() repository.DevicePortRepo {
return repository.NewDevicePortRepo(rm.infra.Conn())
}

View File

@ -0,0 +1,55 @@
package manager
import (
"users_management/m/config"
"users_management/m/usecase"
)
type UsecaseManager interface {
NewUserUsecase() usecase.UsersUsecase
NewAuthUsecase() usecase.AuthUsecase
NewDeviceUsecase() usecase.DeviceUseCase
NewBackboneUsecase() usecase.BackboneUseCase
NewFishboneUsecase() usecase.FishboneUseCase
NewTowerUsecase() usecase.TowerUseCase
NewDevicePortUsecase() usecase.DevicePortUseCase
}
type usecaseManager struct {
repo RepositoryManager
cfg *config.Config
}
func NewUsecaseManager(repo RepositoryManager, cfg *config.Config) UsecaseManager {
return &usecaseManager{repo: repo,cfg: cfg }
}
func (um *usecaseManager) NewUserUsecase() usecase.UsersUsecase {
return usecase.NewUsersUsecase(um.repo.NewUserRepository())
}
func (um *usecaseManager) NewAuthUsecase() usecase.AuthUsecase {
return usecase.NewAuthUsecase(um.repo.NewUserRepository(), um.cfg)
}
func (um *usecaseManager) NewDeviceUsecase() usecase.DeviceUseCase {
return usecase.NewDeviceUseCase(um.repo.NewDeviceRepository())
}
func (um *usecaseManager) NewBackboneUsecase() usecase.BackboneUseCase {
return usecase.NewBackboneUseCase(um.repo.NewBackboneRepository())
}
func (um *usecaseManager) NewFishboneUsecase() usecase.FishboneUseCase {
return usecase.NewFishboneUseCase(um.repo.NewFishboneRepository())
}
func (um *usecaseManager) NewTowerUsecase() usecase.TowerUseCase {
return usecase.NewTowerUseCase(um.repo.NewTowerRepository())
}
func (um *usecaseManager) NewDevicePortUsecase() usecase.DevicePortUseCase {
return usecase.NewDevicePortUseCase(um.repo.NewDevicePortRepository())
}

View File

@ -0,0 +1,9 @@
package req
import "github.com/google/uuid"
type BackboneDTO struct {
DeviceStartID uuid.UUID `json:"dev_start_id"`
DeviceEndID uuid.UUID `json:"dev_end_id"`
CoreAmount int `json:"core_amount"`
}

View File

@ -0,0 +1,8 @@
package req
import "github.com/google/uuid"
type DevicePort struct {
DeviceID uuid.UUID `json:"device_id"`
PortNumber int `json:"port_number"`
}

View File

@ -0,0 +1,11 @@
package req
type DeviceDTO struct {
DeviceCode string `json:"device_code" validate:"required"`
DeviceType string `json:"device_type" validate:"required"`
Longitude float64 `json:"longitude" validate:"required"`
Latitude float64 `json:"latitude" validate:"required"`
PortAmount int `json:"port_amount" validate:"required"`
Status string `json:"status" validate:"required,oneof=active inactive maintenance"`
}

View File

@ -0,0 +1,10 @@
package req
import "github.com/google/uuid"
type FishboneDTO struct {
BackboneID uuid.UUID `json:"bb_id"`
DeviceStartID uuid.UUID `json:"dev_start_id"`
DeviceEndID uuid.UUID `json:"dev_end_id"`
CoreAmount int `json:"core_amount"`
}

View File

@ -0,0 +1,10 @@
package req
import "github.com/google/uuid"
type TowerDTO struct {
DeviceID uuid.UUID `json:"dev_id"`
TowerCode string `json:"tower_code"`
Longitude float64 `json:"longitude"`
Latitude float64 `json:"latitude"`
}

View File

@ -0,0 +1,20 @@
package res
type AuthResponses struct {
Token string `json:"token"`
Detail AuthMeResponse `json:"data"`
}
type AuthMeResponse struct {
Success bool `json:"success"`
Data struct {
NomorInduk string `json:"nomor_induk"`
Username string `json:"username"`
Nama string `json:"nama"`
JenisKelamin string `json:"jenis_kelamin"`
Perusahaan string `json:"perusahaan"`
Cabang string `json:"cabang"`
Departemen string `json:"departemen"`
Jabatan string `json:"jabatan"`
} `json:"data"`
}

View File

@ -0,0 +1,11 @@
package res
type Status struct {
Code int `json:"code"`
Description string `json:"description"`
}
type SingleResponses struct {
Status Status `json:"status"`
Data any `json:"data"`
}

13
model/dto/user_dto.go Normal file
View File

@ -0,0 +1,13 @@
package dto
type UserRegisterDTO struct {
Name string `json:"name" validate:"required"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
RoleID string `json:"role_id" validate:"required,uuid"`
}
type UserLoginDTO struct {
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
}

23
model/entity/backbone.go Normal file
View File

@ -0,0 +1,23 @@
package entity
import (
"time"
"github.com/google/uuid"
)
type Backbone struct {
ID uuid.UUID `json:"id"`
DeviceStartID uuid.UUID `json:"dev_start_id" gorm:"column:dev_start_id"`
DeviceEndID uuid.UUID `json:"dev_end_id" gorm:"column:dev_end_id"`
CoreAmount int `json:"core_amount"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeviceStart Device `gorm:"foreignKey:DeviceStartID"`
DeviceEnd Device `gorm:"foreignKey:DeviceEndID"`
}
func (Backbone) TableName() string {
return "backbone"
}

View File

@ -0,0 +1,21 @@
package entity
import (
"time"
"github.com/google/uuid"
)
type DevicePort struct {
ID uuid.UUID `json:"id"`
DeviceID uuid.UUID `json:"device_id" gorm:"column:device_id"`
PortNumber int `json:"port_number"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Device Device `gorm:"foreignKey:DeviceID"`
}
func (DevicePort) TableName() string {
return "device_ports"
}

29
model/entity/devices.go Normal file
View File

@ -0,0 +1,29 @@
package entity
import (
"time"
"github.com/google/uuid"
)
type DeviceType string
type DeviceStatus string
const (
Odp DeviceType = "ODP"
activeDev DeviceStatus = "active"
inactiveDev DeviceStatus = "inactive"
maintenanceDev DeviceStatus = "maintenance"
)
type Device struct {
ID uuid.UUID `json:"id"`
DeviceCode string `json:"device_code"`
DeviceType DeviceType `json:"device_type"`
Longitude float64 `json:"longitude"`
Latitude float64 `json:"latitude"`
PortAmount int `json:"port_amount"`
Status DeviceStatus `json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

27
model/entity/fishbone.go Normal file
View File

@ -0,0 +1,27 @@
package entity
import (
"time"
"github.com/google/uuid"
)
type Fishbone struct {
ID uuid.UUID `json:"id"`
BackboneID uuid.UUID `json:"backbone_id" gorm:"column:bb_id"`
DeviceStartID uuid.UUID `json:"dev_start_id" gorm:"column:dev_start_id"`
DeviceEndID uuid.UUID `json:"dev_end_id" gorm:"column:dev_end_id"`
CoreAmount int `json:"core_amount"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeviceStart Device `gorm:"foreignKey:DeviceStartID"`
DeviceEnd Device `gorm:"foreignKey:DeviceEndID"`
Backbone Backbone `gorm:"foreignKey:BackboneID"`
}
func (Fishbone) TableName() string {
return "fishbone"
}

10
model/entity/roles.go Normal file
View File

@ -0,0 +1,10 @@
package entity
import "github.com/google/uuid"
type Role struct {
Id uuid.UUID `json:"id"`
Name string `json:"name"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}

23
model/entity/tower.go Normal file
View File

@ -0,0 +1,23 @@
package entity
import (
"time"
"github.com/google/uuid"
)
type Tower struct {
ID uuid.UUID `json:"id"`
DeviceID uuid.UUID`json:"dev_id" gorm:"column:dev_id"`
TowerCode string `json:"tower_code"`
Longitude float64 `json:"longitude"`
Latitude float64 `json:"latitude"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Device Device `gorm:"foreignKey:DeviceID"`
}
func (Tower) TableName() string {
return "towers"
}

18
model/entity/users.go Normal file
View File

@ -0,0 +1,18 @@
package entity
import (
"time"
"github.com/google/uuid"
)
type User struct {
ID uuid.UUID `json:"id"`
RoleID uuid.UUID `json:"role_id"`
Role Role `json:"role"`
Name string `json:"name"`
Username string `json:"username"`
Password string `json:"password"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

View File

@ -0,0 +1,48 @@
package repository
import (
"users_management/m/model/entity"
"gorm.io/gorm"
)
type BackboneRepo interface {
Post(backbone entity.Backbone) error
GetAll() ([]entity.Backbone, error)
Update(backbone entity.Backbone) error
}
type backboneRepo struct {
db *gorm.DB
}
func NewBackboneRepo(db *gorm.DB) BackboneRepo {
return &backboneRepo{
db: db,
}
}
func (r *backboneRepo) Post(backbone entity.Backbone) error {
err := r.db.Create(&backbone).Error
if err != nil {
return err
}
return nil
}
func (r *backboneRepo) GetAll() ([]entity.Backbone, error) {
var backbones []entity.Backbone
err := r.db.Find(&backbones).Error
if err != nil {
return backbones, err
}
return backbones, nil
}
func (r *backboneRepo) Update(backbone entity.Backbone) error {
err := r.db.Save(&backbone).Error
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,48 @@
package repository
import (
"users_management/m/model/entity"
"gorm.io/gorm"
)
type DevicePortRepo interface {
Post(devicePort entity.DevicePort) error
GetAll() ([]entity.DevicePort, error)
Update(devicePort entity.DevicePort) error
}
type devicePortRepo struct {
db *gorm.DB
}
func NewDevicePortRepo(db *gorm.DB) DevicePortRepo {
return &devicePortRepo{
db: db,
}
}
func (r *devicePortRepo) Post(devicePort entity.DevicePort) error {
err := r.db.Create(&devicePort).Error
if err != nil {
return err
}
return nil
}
func (r *devicePortRepo) GetAll() ([]entity.DevicePort, error) {
var devicePorts []entity.DevicePort
err := r.db.Find(&devicePorts).Error
if err != nil {
return devicePorts, err
}
return devicePorts, nil
}
func (r *devicePortRepo) Update(devicePort entity.DevicePort) error {
err := r.db.Save(&devicePort).Error
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,47 @@
package repository
import (
"users_management/m/model/entity"
"gorm.io/gorm"
)
type DevicesRepo interface {
Post(device entity.Device) error
GetAll() ([]entity.Device, error)
Update(device entity.Device) error
}
type devicesRepo struct {
db *gorm.DB
}
func NewDevicesRepo(db *gorm.DB) DevicesRepo {
return &devicesRepo{
db: db,
}
}
func (r *devicesRepo) Post(device entity.Device) error {
err := r.db.Create(&device).Error
if err != nil {
return err
}
return nil
}
func (r *devicesRepo) GetAll() ([]entity.Device, error) {
var devices []entity.Device
err := r.db.Find(&devices).Error
if err != nil {
return devices, err
}
return devices, nil
}
func (r *devicesRepo) Update(device entity.Device) error {
err := r.db.Save(&device).Error
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,48 @@
package repository
import (
"users_management/m/model/entity"
"gorm.io/gorm"
)
type FishboneRepo interface {
Post(fishbone entity.Fishbone) error
GetAll() ([]entity.Fishbone, error)
Update(fishbone entity.Fishbone) error
}
type fishboneRepo struct {
db *gorm.DB
}
func NewFishboneRepo(db *gorm.DB) FishboneRepo {
return &fishboneRepo{
db: db,
}
}
func (r *fishboneRepo) Post(fishbone entity.Fishbone) error {
err := r.db.Create(&fishbone).Error
if err != nil {
return err
}
return nil
}
func (r *fishboneRepo) GetAll() ([]entity.Fishbone, error) {
var fishbones []entity.Fishbone
err := r.db.Find(&fishbones).Error
if err != nil {
return fishbones, err
}
return fishbones, nil
}
func (r *fishboneRepo) Update(fishbone entity.Fishbone) error {
err := r.db.Save(&fishbone).Error
if err != nil {
return err
}
return nil
}

48
repository/tower_repo.go Normal file
View File

@ -0,0 +1,48 @@
package repository
import (
"users_management/m/model/entity"
"gorm.io/gorm"
)
type TowerRepo interface {
Post(tower entity.Tower) error
GetAll() ([]entity.Tower, error)
Update(tower entity.Tower) error
}
type towerRepo struct {
db *gorm.DB
}
func NewTowerRepo(db *gorm.DB) TowerRepo {
return &towerRepo{
db: db,
}
}
func (r *towerRepo) Post(tower entity.Tower) error {
err := r.db.Create(&tower).Error
if err != nil {
return err
}
return nil
}
func (r *towerRepo) GetAll() ([]entity.Tower, error) {
var towers []entity.Tower
err := r.db.Find(&towers).Error
if err != nil {
return towers, err
}
return towers, nil
}
func (r *towerRepo) Update(tower entity.Tower) error {
err := r.db.Save(&tower).Error
if err != nil {
return err
}
return nil
}

50
repository/users_repo.go Normal file
View File

@ -0,0 +1,50 @@
package repository
import (
"users_management/m/model/entity"
"gorm.io/gorm"
)
type UsersRepo interface {
Post(user entity.User) error
GetRoleByDepartment(departmentName string) (entity.Role, error)
GetUserByUsername(username string) (entity.User, error)
}
type usersRepo struct {
db *gorm.DB
}
func NewUsersRepo(db *gorm.DB) UsersRepo {
return &usersRepo{
db: db,
}
}
func (r *usersRepo) Post(user entity.User) error {
err := r.db.Create(&user).Error
if err != nil {
return err
}
return nil
}
func (r *usersRepo) GetRoleByDepartment(departmentName string) (entity.Role, error) {
var role entity.Role
err := r.db.Where("name = ?", departmentName).First(&role).Error
if err != nil {
return role, err
}
return role, nil
}
func (r *usersRepo) GetUserByUsername(username string) (entity.User, error) {
var users entity.User
err := r.db.Where("username = ?", username).First(&users).Error
if err != nil {
return users, err
}
return users, nil
}

181
usecase/auth_usecase.go Normal file
View File

@ -0,0 +1,181 @@
package usecase
import (
"bytes"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"time"
"users_management/m/config"
"users_management/m/model/dto"
"users_management/m/model/dto/res"
"users_management/m/model/entity"
"users_management/m/repository"
"users_management/m/utils"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
"gorm.io/gorm"
)
type AuthUsecase interface {
Login(login dto.UserLoginDTO) (string, error)
Logout(token string) error
}
type authUsecase struct {
userRepo repository.UsersRepo
validate *validator.Validate
cfg *config.Config
}
func NewAuthUsecase(userRepo repository.UsersRepo, cfg *config.Config) AuthUsecase {
return &authUsecase{
userRepo: userRepo,
validate: validator.New(),
cfg: cfg,
}
}
func (u *authUsecase) Login(login dto.UserLoginDTO) (string, error) {
err := u.validate.Struct(login)
if err != nil {
return "", err
}
payload, err := json.Marshal(login)
if err != nil {
return "", err
}
req, err := http.NewRequest("POST", u.cfg.LoginAPI, bytes.NewBuffer(payload))
if err != nil {
return "", err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", errors.New("wrong password or username")
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
var authResponse res.AuthResponses
err = json.Unmarshal(body, &authResponse)
if err != nil {
return "", err
}
token := authResponse.Token
meReq, err := http.NewRequest("POST", u.cfg.AuthMeAPI, nil)
if err != nil {
return "", err
}
meReq.Header.Set("Authorization", "Bearer "+token)
meReq.Header.Set("Accept", "application/json")
meResp, err := client.Do(meReq)
if err != nil {
return "",err
}
defer meResp.Body.Close()
if meResp.StatusCode != http.StatusOK {
return "", errors.New("failed to validate token: " + meResp.Status)
}
meBody, err := ioutil.ReadAll(meResp.Body)
if err != nil {
return "", err
}
var meResponse res.AuthMeResponse
err = json.Unmarshal(meBody, &meResponse)
if err != nil {
return "", err
}
departemen := meResponse.Data.Departemen
if departemen != "Teknisi" {
return "", errors.New("user is not a technician")
}
role , err := u.userRepo.GetRoleByDepartment(departemen)
if err != nil {
return "", err
}
password, err := utils.HashPassword(login.Password)
if err != nil {
return "error while hasing password: ", err
}
isUserExist, err := u.userRepo.GetUserByUsername(login.Username)
if isUserExist.ID != uuid.Nil {
// Validate the password
if !utils.CheckPasswordHash(login.Password, isUserExist.Password) {
return "", errors.New("incorrect password")
}
return token, nil
}else if err != nil && err != gorm.ErrRecordNotFound {
return "ERROR WHILE SEARCHING USERNAME", err
}
user := entity.User{
ID: uuid.New(),
Name: meResponse.Data.Nama,
Username: login.Username,
Password: password,
RoleID: role.Id,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err = u.userRepo.Post(user)
if err != nil {
return "", err
}
return token,nil
}
func (u *authUsecase) Logout(token string) error {
req, err := http.NewRequest("POST", u.cfg.LogoutAPI, nil)
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Accept", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return errors.New("failed to logout: " + resp.Status)
}
return nil
}

View File

@ -0,0 +1,56 @@
package usecase
import (
"fmt"
"time"
"users_management/m/model/dto/req"
"users_management/m/model/entity"
"users_management/m/repository"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
)
type BackboneUseCase interface {
CreateBackbone(backbone req.BackboneDTO) error
GetAllBackbone() ([]entity.Backbone, error)
}
type backboneUseCase struct {
backboneRepo repository.BackboneRepo
validate *validator.Validate
}
func NewBackboneUseCase(backboneRepo repository.BackboneRepo) BackboneUseCase {
return &backboneUseCase{
backboneRepo: backboneRepo,
validate: validator.New(),
}
}
func (u *backboneUseCase) CreateBackbone(backbone req.BackboneDTO) error {
err := u.validate.Struct(backbone)
if err != nil {
return fmt.Errorf("validation error: %w", err)
}
newBackbone := entity.Backbone{
ID: uuid.New(),
DeviceStartID: backbone.DeviceStartID,
DeviceEndID: backbone.DeviceEndID,
CoreAmount: backbone.CoreAmount,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
return u.backboneRepo.Post(newBackbone)
}
func (u *backboneUseCase) GetAllBackbone() ([]entity.Backbone, error) {
backbones, err := u.backboneRepo.GetAll()
if err != nil {
return backbones, err
}
return backbones, nil
}

View File

@ -0,0 +1,53 @@
package usecase
import (
"time"
"users_management/m/model/dto/req"
"users_management/m/model/entity"
"users_management/m/repository"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
)
type DevicePortUseCase interface {
CreateDevicePort(devicePort req.DevicePort) error
GetAllDevicePort() ([]entity.DevicePort, error)
}
type devicePortUseCase struct {
devicePortRepo repository.DevicePortRepo
validate *validator.Validate
}
func NewDevicePortUseCase(devicePortRepo repository.DevicePortRepo) DevicePortUseCase {
return &devicePortUseCase{
devicePortRepo: devicePortRepo,
validate: validator.New(),
}
}
func (u *devicePortUseCase) CreateDevicePort(devicePort req.DevicePort) error {
err := u.validate.Struct(devicePort)
if err != nil {
return err
}
newDevicePort := entity.DevicePort{
ID: uuid.New(),
DeviceID: devicePort.DeviceID,
PortNumber: devicePort.PortNumber,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
return u.devicePortRepo.Post(newDevicePort)
}
func (u *devicePortUseCase) GetAllDevicePort() ([]entity.DevicePort, error) {
devicePorts, err := u.devicePortRepo.GetAll()
if err != nil {
return devicePorts, err
}
return devicePorts, nil
}

58
usecase/device_usecase.go Normal file
View File

@ -0,0 +1,58 @@
package usecase
import (
"fmt"
"time"
"users_management/m/model/dto/req"
"users_management/m/model/entity"
"users_management/m/repository"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
)
type DeviceUseCase interface {
CreateDevice(device req.DeviceDTO) error
GetAllDevices() ([]entity.Device, error)
}
type deviceUseCase struct {
deviceRepo repository.DevicesRepo
validate *validator.Validate
}
func NewDeviceUseCase(deviceRepo repository.DevicesRepo) DeviceUseCase {
return &deviceUseCase{
deviceRepo: deviceRepo,
validate: validator.New(),
}
}
func (u *deviceUseCase) CreateDevice(device req.DeviceDTO) error {
err := u.validate.Struct(device)
if err != nil {
return fmt.Errorf("validation error: %w", err)
}
newDevice := entity.Device{
ID: uuid.New(),
DeviceCode: device.DeviceCode,
DeviceType: entity.DeviceType(device.DeviceType),
Longitude: device.Longitude,
Latitude: device.Latitude,
PortAmount: device.PortAmount,
Status: entity.DeviceStatus(device.Status),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
return u.deviceRepo.Post(newDevice)
}
func (u *deviceUseCase) GetAllDevices() ([]entity.Device, error) {
devices, err := u.deviceRepo.GetAll()
if err != nil {
return devices, err
}
return devices, nil
}

View File

@ -0,0 +1,55 @@
package usecase
import (
"time"
"users_management/m/model/dto/req"
"users_management/m/model/entity"
"users_management/m/repository"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
)
type FishboneUseCase interface {
CreateFishbone(fishbone req.FishboneDTO) error
GetAllFishbone() ([]entity.Fishbone, error)
}
type fishboneUsecase struct {
fishboneRepo repository.FishboneRepo
validate *validator.Validate
}
func NewFishboneUseCase(fishboneRepo repository.FishboneRepo) FishboneUseCase {
return &fishboneUsecase{
fishboneRepo: fishboneRepo,
validate: validator.New(),
}
}
func (u *fishboneUsecase) CreateFishbone(fishbone req.FishboneDTO) error {
err := u.validate.Struct(fishbone)
if err != nil {
return err
}
newFishbone := entity.Fishbone{
ID: uuid.New(),
BackboneID: fishbone.BackboneID,
DeviceStartID: fishbone.DeviceStartID,
DeviceEndID: fishbone.DeviceEndID,
CoreAmount: fishbone.CoreAmount,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
return u.fishboneRepo.Post(newFishbone)
}
func (u *fishboneUsecase) GetAllFishbone() ([]entity.Fishbone, error) {
fishbones, err := u.fishboneRepo.GetAll()
if err != nil {
return fishbones, err
}
return fishbones, nil
}

55
usecase/tower_usecase.go Normal file
View File

@ -0,0 +1,55 @@
package usecase
import (
"time"
"users_management/m/model/dto/req"
"users_management/m/model/entity"
"users_management/m/repository"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
)
type TowerUseCase interface {
Post(tower req.TowerDTO) error
GetAll() ([]entity.Tower, error)
}
type towerUsecase struct {
towerRepo repository.TowerRepo
validate *validator.Validate
}
func NewTowerUseCase(towerRepo repository.TowerRepo) TowerUseCase {
return &towerUsecase{
towerRepo: towerRepo,
validate: validator.New(),
}
}
func (u *towerUsecase) Post(tower req.TowerDTO) error {
err := u.validate.Struct(tower)
if err != nil {
return err
}
newTower := entity.Tower{
ID: uuid.New(),
DeviceID: tower.DeviceID,
TowerCode: tower.TowerCode,
Longitude: tower.Longitude,
Latitude: tower.Latitude,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
return u.towerRepo.Post(newTower)
}
func (u *towerUsecase) GetAll() ([]entity.Tower, error) {
towers, err := u.towerRepo.GetAll()
if err != nil {
return towers, err
}
return towers, nil
}

42
usecase/users_usecase.go Normal file
View File

@ -0,0 +1,42 @@
package usecase
import (
"users_management/m/model/entity"
"users_management/m/repository"
"github.com/google/uuid"
)
type UsersUsecase interface {
GetRoleByDepartment(departmentName string) (uuid.UUID, error)
GetUserByUsername(username string) (entity.User, error)
}
type usersUsecase struct {
userRepo repository.UsersRepo
}
func NewUsersUsecase(userRepo repository.UsersRepo) UsersUsecase {
return &usersUsecase{
userRepo: userRepo,
}
}
func (u *usersUsecase) GetRoleByDepartment(departmentName string) (uuid.UUID, error) {
role, err := u.userRepo.GetRoleByDepartment(departmentName)
if err != nil {
return uuid.Nil, err
}
return role.Id, nil
}
func (u *usersUsecase) GetUserByUsername(username string) (entity.User, error) {
users, err := u.userRepo.GetUserByUsername(username)
if err != nil {
return users, err
}
return users, nil
}

27
utils/common/json_res.go Normal file
View File

@ -0,0 +1,27 @@
package common
import (
"net/http"
"users_management/m/model/dto/res"
"github.com/gin-gonic/gin"
)
func SingleResponses(ctx *gin.Context, description string, data any) {
ctx.JSON(http.StatusOK, res.SingleResponses{
Status: res.Status{
Code: http.StatusCreated,
Description: description,
},
Data: data,
})
}
func ErrorResponses(ctx *gin.Context, code int, description string) {
ctx.JSON(code, res.SingleResponses{
Status: res.Status{
Code: code,
Description: description,
},
})
}

16
utils/common/logger.go Normal file
View File

@ -0,0 +1,16 @@
package common
import (
"github.com/gin-gonic/gin"
"os"
)
func LoggingToFile() gin.HandlerFunc {
logFile, err := os.OpenFile("gin.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
panic("Failed to open log file: " + err.Error())
}
gin.DefaultWriter = logFile
return gin.Logger()
}

17
utils/utils.go Normal file
View File

@ -0,0 +1,17 @@
package utils
import "golang.org/x/crypto/bcrypt"
func HashPassword(password string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
panic(err)
}
password = string(hash)
return password, nil
}
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}