Skip to content

Commit 19c3185

Browse files
committed
refactor(event,user): update author and social fields
- Change Event's `author` field to `author_id` (int) and add proper GORM relation to User. - Update EventDTO to reflect new structure and fields. - Update repository and usecase logic to use `author_id` and fetch author username for DTO. - Add migration to rename `author` to `author_id` and ensure correct type. - Rename User's social fields (`github`, `linkedin`, `personal_web`) to `github_url`, `linkedin_url`, and `personal_web_url` in model and migrations. - Update user profile update logic and seeders to match new field names. - Add session_type to events table if missing.
1 parent 1782d03 commit 19c3185

11 files changed

+237
-75
lines changed

app/events/repository/get_event.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,39 @@ import (
66
"github.com/hammer-code/lms-be/domain"
77
)
88

9-
func (repo *repository) GetEvent(ctx context.Context, eventID uint) (data domain.Event, err error) {
9+
func (repo *repository) GetEvent(ctx context.Context, eventID uint) (dataDTO domain.EventDTO, err error) {
1010
db := repo.db.DB(ctx).Model(&domain.Event{})
1111

12-
err = db.Where("id = ?", eventID).First(&data).Error
12+
data := domain.Event{}
1313

14-
return data, err
14+
err = db.Where("id = ?", eventID).Preload("Tags").Preload("Speakers").Preload("Author").First(&data).Error
15+
16+
if err == nil {
17+
dataDTO = domain.EventDTO{
18+
ID: data.ID,
19+
Title: data.Title,
20+
Description: data.Description,
21+
Slug: data.Slug,
22+
Image: data.Image,
23+
Date: data.Date,
24+
Type: data.Type,
25+
Location: data.Location,
26+
Duration: data.Duration,
27+
Capacity: data.Capacity,
28+
Status: data.Status,
29+
Tags: data.Tags,
30+
Speakers: data.Speakers,
31+
SessionType: data.SessionType,
32+
RegistrationLink: data.RegistrationLink,
33+
Price: data.Price,
34+
ReservationStartDate: data.ReservationStartDate,
35+
ReservationEndDate: data.ReservationEndDate,
36+
Author: data.Author.Username,
37+
CreatedAt: data.CreatedAt,
38+
UpdatedAt: data.UpdatedAt,
39+
DeletedAt: data.DeletedAt,
40+
}
41+
}
42+
43+
return dataDTO, err
1544
}

app/events/repository/get_events.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,5 @@ func (repo *repository) GetEvents(ctx context.Context, filter domain.EventFilter
4141
}
4242

4343
return int(totalData), data, err
44-
}
44+
}
45+

app/events/usecase/create_event.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66

77
"github.com/hammer-code/lms-be/domain"
8+
contextkey "github.com/hammer-code/lms-be/pkg/context_key"
89
"github.com/hammer-code/lms-be/utils"
910
)
1011

@@ -20,11 +21,13 @@ func (uc usecase) CreateEvent(ctx context.Context, payload domain.CreateEventPay
2021
return err
2122
}
2223

24+
userData := ctx.Value(contextkey.UserKey).(domain.User)
25+
2326
err = uc.dbTX.StartTransaction(ctx, func(txCtx context.Context) error {
2427
data := domain.Event{
2528
Title: payload.Title,
2629
Description: payload.Description,
27-
Author: payload.Author,
30+
AuthorID: userData.ID,
2831
Image: dataImage.FileName,
2932
Date: payload.Date,
3033
Slug: payload.Slug,
@@ -37,7 +40,7 @@ func (uc usecase) CreateEvent(ctx context.Context, payload domain.CreateEventPay
3740
ReservationEndDate: payload.ReservationEndDate,
3841
Price: payload.Price,
3942
Status: payload.Status,
40-
AdditionalLink: payload.AdditionalLink,
43+
AdditionalLink: payload.AdditionalLink,
4144
}
4245

4346
eventID, err := uc.repository.CreateEvent(txCtx, data)

app/events/usecase/get_event_general.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"github.com/hammer-code/lms-be/utils"
1010
)
1111

12-
func (uc usecase) GetEventByID(ctx context.Context, id uint) (domain.Event, error) {
12+
func (uc usecase) GetEventByID(ctx context.Context, id uint) (domain.EventDTO, error) {
1313
resp, err := uc.repository.GetEvent(ctx, id)
1414
if err != nil {
1515
err = utils.NewInternalServerError(ctx, err)

app/events/usecase/update_event.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@ import (
55
"time"
66

77
"github.com/hammer-code/lms-be/domain"
8+
contextkey "github.com/hammer-code/lms-be/pkg/context_key"
89
"github.com/hammer-code/lms-be/utils"
910
"gopkg.in/guregu/null.v4"
1011
)
1112

1213
func (uc usecase) UpdateEvent(ctx context.Context, id uint, payload domain.UpdateEventPayload) error {
14+
15+
userData := ctx.Value(contextkey.UserKey).(domain.User)
16+
1317
err := uc.repository.UpdateEvent(ctx, domain.Event{
1418
ID: id,
1519
Title: payload.Title,
1620
Description: payload.Description,
1721
Slug: payload.Slug,
18-
Author: payload.Author,
22+
AuthorID: userData.ID,
1923
Image: payload.FileName,
2024
Date: payload.Date,
2125
Type: payload.Type,

database/migration/20250726150819_table_add_column_additional_link.sql

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,23 @@
22
-- +goose StatementBegin
33
SELECT 'up SQL query';
44

5-
ALTER TABLE events
6-
ADD COLUMN additional_link TEXT;
5+
DO $$
6+
BEGIN
7+
-- Check if the column already exists
8+
IF NOT EXISTS (
9+
SELECT 1 FROM information_schema.columns
10+
WHERE table_name='events' AND column_name='additional_link'
11+
) THEN
12+
ALTER TABLE events
13+
ADD COLUMN additional_link TEXT;
14+
END IF;
15+
END $$;
716
-- +goose StatementEnd
817

918
-- +goose Down
1019
-- +goose StatementBegin
1120
SELECT 'down SQL query';
1221

1322
ALTER TABLE events
14-
DROP COLUMN additional_link;
23+
DROP COLUMN IF EXISTS additional_link;
1524
-- +goose StatementEnd
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
-- +goose Up
2+
-- +goose StatementBegin
3+
DO $$
4+
BEGIN
5+
-- Check if github column exists and github_url doesn't
6+
IF EXISTS (
7+
SELECT 1 FROM information_schema.columns
8+
WHERE table_name='users' AND column_name='github'
9+
) AND NOT EXISTS (
10+
SELECT 1 FROM information_schema.columns
11+
WHERE table_name='users' AND column_name='github_url'
12+
) THEN
13+
ALTER TABLE "public"."users" RENAME COLUMN "github" TO "github_url";
14+
END IF;
15+
16+
-- Check if linkedin column exists and linkedin_url doesn't
17+
IF EXISTS (
18+
SELECT 1 FROM information_schema.columns
19+
WHERE table_name='users' AND column_name='linkedin'
20+
) AND NOT EXISTS (
21+
SELECT 1 FROM information_schema.columns
22+
WHERE table_name='users' AND column_name='linkedin_url'
23+
) THEN
24+
ALTER TABLE "public"."users" RENAME COLUMN "linkedin" TO "linkedin_url";
25+
END IF;
26+
27+
-- Check if personal_web column exists and personal_web_url doesn't
28+
IF EXISTS (
29+
SELECT 1 FROM information_schema.columns
30+
WHERE table_name='users' AND column_name='personal_web'
31+
) AND NOT EXISTS (
32+
SELECT 1 FROM information_schema.columns
33+
WHERE table_name='users' AND column_name='personal_web_url'
34+
) THEN
35+
ALTER TABLE "public"."users" RENAME COLUMN "personal_web" TO "personal_web_url";
36+
END IF;
37+
END $$;
38+
-- +goose StatementEnd
39+
40+
-- +goose Down
41+
-- +goose StatementBegin
42+
DO $$
43+
BEGIN
44+
-- Only rename back if the new columns exist and old ones don't
45+
IF EXISTS (
46+
SELECT 1 FROM information_schema.columns
47+
WHERE table_name='users' AND column_name='github_url'
48+
) THEN
49+
ALTER TABLE "public"."users" RENAME COLUMN "github_url" TO "github";
50+
ALTER TABLE "public"."users" RENAME COLUMN "linkedin_url" TO "linkedin";
51+
ALTER TABLE "public"."users" RENAME COLUMN "personal_web_url" TO "personal_web";
52+
END IF;
53+
END $$;
54+
-- +goose StatementEnd
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
-- +goose Up
2+
-- +goose StatementBegin
3+
DO $$
4+
BEGIN
5+
-- Check if author column exists and author_id doesn't
6+
IF EXISTS (
7+
SELECT 1 FROM information_schema.columns
8+
WHERE table_name='events' AND column_name='author'
9+
) AND NOT EXISTS (
10+
SELECT 1 FROM information_schema.columns
11+
WHERE table_name='events' AND column_name='author_id'
12+
) THEN
13+
-- Rename and change type to INT if needed
14+
ALTER TABLE events RENAME COLUMN author TO author_id;
15+
ALTER TABLE events ALTER COLUMN author_id TYPE INT USING (author_id::integer);
16+
ELSIF NOT EXISTS (
17+
SELECT 1 FROM information_schema.columns
18+
WHERE table_name='events' AND column_name='author_id'
19+
) THEN
20+
-- If neither column exists, add author_id as INT
21+
ALTER TABLE events ADD COLUMN author_id INT;
22+
END IF;
23+
24+
-- Check if session_type field exists, add it if it doesn't
25+
IF NOT EXISTS (
26+
SELECT 1 FROM information_schema.columns
27+
WHERE table_name='events' AND column_name='session_type'
28+
) THEN
29+
ALTER TABLE events ADD COLUMN session_type TEXT;
30+
END IF;
31+
END $$;
32+
-- +goose StatementEnd
33+
34+
-- +goose Down
35+
-- +goose StatementBegin
36+
ALTER TABLE events RENAME COLUMN author_id TO author;
37+
ALTER TABLE events DROP COLUMN IF EXISTS session_type;
38+
-- +goose StatementEnd
Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
1+
-- +goose NO TRANSACTION
12
-- +goose Up
23
-- +goose StatementBegin
3-
4-
TRUNCATE TABLE "public"."users" RESTART IDENTITY CASCADE;
5-
6-
INSERT INTO "public"."users" (
7-
"username", "email", "password", "role", "fullname",
8-
"date_of_birth", "gender", "phone_number", "address",
9-
"github", "linkedin", "personal_web", "created_at", "updated_at"
4+
TRUNCATE TABLE "public"."events" RESTART IDENTITY CASCADE;
5+
INSERT INTO "public"."events" (
6+
"id", "title", "description", "author_id", "image", "date",
7+
"reservation_start_date", "reservation_end_date", "type",
8+
"location", "duration", "status", "price", "capacity",
9+
"registration_link", "session_type", "created_at", "updated_at"
1010
) VALUES
11-
-- password : passowrd
12-
('admin', '[email protected]', '$2a$10$zzJJ6MKKBgJT0CfT7rjnWeCAfSRIG6VhBdoqSIWi1VjwBfsp6XcT.', 'admin', 'Admin User',
13-
'1990-01-01', 'Male', '123456789', '123 Admin St',
14-
'github.com/admin', 'linkedin.com/in/admin', 'admin.com', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
15-
11+
(1, 'Web Development Workshop', 'Learn modern web development techniques',
12+
1, 'workshop_banner.jpg', '2025-06-15 09:00:00',
13+
'2025-05-15 00:00:00', '2025-06-14 23:59:59', 'workshop',
14+
'Tech Hub, Floor 3', '8 hours', 'upcoming', 150.00, 30,
15+
'https://example.com/register/web-dev', 'offline', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
16+
17+
(2, 'Data Science Conference', 'Annual conference for data scientists',
18+
1, 'conference_logo.png', '2025-07-20 08:30:00',
19+
'2025-06-01 00:00:00', '2025-07-15 23:59:59', 'conference',
20+
'Convention Center', '3 days', 'upcoming', 299.99, 200,
21+
'https://example.com/register/data-conf', 'hybrid', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
22+
23+
(3, 'Mobile App Hackathon', '48-hour app building competition',
24+
1, 'hackathon_poster.jpg', '2025-08-10 10:00:00',
25+
'2025-07-01 00:00:00', '2025-08-05 23:59:59', 'hackathon',
26+
'Innovation Labs', '48 hours', 'upcoming', 50.00, 100,
27+
'https://example.com/register/app-hackathon', 'online', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
28+
SELECT setval('events_id_seq', (SELECT MAX(id) FROM events), true);
1629
-- +goose StatementEnd
1730

1831
-- +goose Down
1932
-- +goose StatementBegin
20-
DELETE FROM "public"."users" WHERE "username" IN ('admin', 'johndoe', 'janedoe');
33+
TRUNCATE TABLE "public"."events" RESTART IDENTITY CASCADE;
2134
-- +goose StatementEnd

domain/event.go

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ type EventRepository interface {
1919
GetEvents(ctx context.Context, filter EventFilter) (tData int, data []Event, err error)
2020
CreateEventPay(ctx context.Context, event EventPay) (uint, error)
2121
CreateRegistrationEvent(ctx context.Context, event RegistrationEvent) (uint, error)
22-
GetEvent(ctx context.Context, eventID uint) (data Event, err error)
22+
GetEvent(ctx context.Context, eventID uint) (data EventDTO, err error)
2323
DeleteEvent(ctx context.Context, eventID uint) (err error)
2424
GetRegistrationEvent(ctx context.Context, orderNo string) (data RegistrationEvent, err error)
2525
ListRegistration(ctx context.Context, filter EventFilter, email string) (tData int, data []RegistrationEvent, err error)
@@ -36,7 +36,7 @@ type EventUsecase interface {
3636
GetEvents(ctx context.Context, filter EventFilter) (data []Event, pagination Pagination, err error)
3737
CreateRegistrationEvent(ctx context.Context, payload RegisterEventPayload) (RegisterEventResponse, error)
3838
CreateEventPay(ctx context.Context, payload EventPayPayload) error
39-
GetEventByID(ctx context.Context, id uint) (resp Event, err error)
39+
GetEventByID(ctx context.Context, id uint) (resp EventDTO, err error)
4040
DeleteEvent(ctx context.Context, id uint) (err error)
4141
RegistrationStatus(ctx context.Context, orderNo string) (resp RegisterStatusResponse, err error)
4242
ListRegistration(ctx context.Context, filter EventFilter) (resp []RegistrationEvent, pagination Pagination, err error)
@@ -64,21 +64,20 @@ type Event struct {
6464
Title string `json:"title" `
6565
Description string `json:"description"`
6666
Slug string `json:"slug"`
67-
Author string `json:"author"`
67+
AuthorID int `json:"author_id"`
68+
Author User `gorm:"foreignKey:AuthorID;references:ID"` // Ensure foreign key is correctly referenced
6869
Image string `json:"image"`
6970
Date null.Time `json:"date"`
7071
Type string `json:"type"`
7172
Location string `json:"location"`
7273
Duration string `json:"duration"`
7374
Capacity int `json:"capacity"`
74-
Status string `json:"status"` // comming soon
75+
Status string `json:"status"` // Conference, Tech Talk, Workshop, Webinar, etc.
7576
Tags []EventTag `gorm:"foreignKey:EventID;constraint:OnDelete:CASCADE;"` // Ensure foreign key is correctly referenced
7677
Speakers []EventSpeaker `gorm:"foreignKey:EventID;constraint:OnDelete:CASCADE;"` // Ensure foreign key is correctly referenced
78+
SessionType string `json:"session_type"` // online, offline, hybrid
7779
RegistrationLink string `json:"registration_link"`
7880
Price float64 `json:"price"` // 0 == free
79-
CreatedBy int `json:"created_by"`
80-
UpdatedBy int `json:"updated_by"`
81-
DeletedBy int `json:"deleted_by"`
8281
ReservationStartDate null.Time `json:"reservation_start_date"`
8382
ReservationEndDate null.Time `json:"reservation_end_date"`
8483
CreatedAt time.Time `json:"created_at"`
@@ -156,17 +155,29 @@ type UpdateEventPayload struct {
156155
}
157156

158157
type EventDTO struct {
159-
ID int `json:"id"`
160-
Title string `json:"title"`
161-
Description string `json:"description"`
162-
Author string `json:"author"`
163-
ImageEvent string `json:"image_event"`
164-
DateEvent null.Time `json:"date_event"`
165-
Type string `json:"type"`
166-
Location string `json:"location"`
167-
Duration string `json:"duration"`
168-
Capacity int `json:"capacity"`
169-
RegistrationLink string `json:"registration_link"`
158+
ID uint `json:"id" gorm:"primarykey"`
159+
Title string `json:"title" `
160+
Description string `json:"description"`
161+
Slug string `json:"slug"`
162+
Author string `json:"author"`
163+
Image string `json:"image"`
164+
Date null.Time `json:"date"`
165+
Type string `json:"type"`
166+
Location string `json:"location"`
167+
Duration string `json:"duration"`
168+
Capacity int `json:"capacity"`
169+
Status string `json:"status"` // Conference, Tech Talk, Workshop, Webinar, etc.
170+
Tags []EventTag `gorm:"foreignKey:EventID;constraint:OnDelete:CASCADE;"` // Ensure foreign key is correctly referenced
171+
Speakers []EventSpeaker `gorm:"foreignKey:EventID;constraint:OnDelete:CASCADE;"` // Ensure foreign key is correctly referenced
172+
SessionType string `json:"session_type"` // online, offline, hybrid
173+
RegistrationLink string `json:"registration_link"`
174+
Price float64 `json:"price"` // 0 == free
175+
ReservationStartDate null.Time `json:"reservation_start_date"`
176+
ReservationEndDate null.Time `json:"reservation_end_date"`
177+
CreatedAt time.Time `json:"created_at"`
178+
UpdatedAt null.Time `json:"updated_at"`
179+
DeletedAt null.Time `json:"deleted_at"`
180+
AdditionalLink string `json:"additional_link"`
170181
}
171182

172183
type UpdateEvenPayload struct {

0 commit comments

Comments
 (0)