Skip to content

Commit 7005e27

Browse files
authored
Merge pull request #97 from RealTeamRocket/96-homepage
some basic stuff
2 parents a8d91d5 + d33d521 commit 7005e27

35 files changed

+1851
-1306
lines changed

mobile_app/pubspec.lock

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ packages:
2121
dependency: transitive
2222
description:
2323
name: async
24-
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
24+
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
2525
url: "https://pub.dev"
2626
source: hosted
27-
version: "2.12.0"
27+
version: "2.13.0"
2828
boolean_selector:
2929
dependency: transitive
3030
description:
@@ -133,10 +133,10 @@ packages:
133133
dependency: transitive
134134
description:
135135
name: fake_async
136-
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
136+
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
137137
url: "https://pub.dev"
138138
source: hosted
139-
version: "1.3.2"
139+
version: "1.3.3"
140140
ffi:
141141
dependency: transitive
142142
description:
@@ -540,10 +540,10 @@ packages:
540540
dependency: transitive
541541
description:
542542
name: leak_tracker
543-
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
543+
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
544544
url: "https://pub.dev"
545545
source: hosted
546-
version: "10.0.8"
546+
version: "10.0.9"
547547
leak_tracker_flutter_testing:
548548
dependency: transitive
549549
description:
@@ -1041,10 +1041,10 @@ packages:
10411041
dependency: transitive
10421042
description:
10431043
name: vm_service
1044-
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
1044+
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
10451045
url: "https://pub.dev"
10461046
source: hosted
1047-
version: "14.3.1"
1047+
version: "15.0.0"
10481048
web:
10491049
dependency: transitive
10501050
description:

rocket-backend/integration-tests/mocks/database_mock.go

Lines changed: 63 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,45 +10,48 @@ import (
1010
)
1111

1212
type MockDB struct {
13-
ExecuteRawSQLFunc func(query string) (sql.Result, error)
14-
QueryRowFunc func(query string, args ...interface{}) *sql.Row
15-
HealthFunc func() map[string]string
16-
CloseFunc func() error
17-
SaveCredentialsFunc func(creds types.Credentials) error
18-
GetUserByEmailFunc func(email string) (types.Credentials, error)
19-
CheckEmailFunc func(email string) error
20-
SaveUserProfileFunc func(user types.User) error
21-
GetUserByIDFunc func(userID uuid.UUID) (types.User, error)
22-
UpdateRocketPointsFunc func(userID uuid.UUID, rocketPoints int) error
23-
GetRocketPointsByUserIDFunc func(userID uuid.UUID) (int, error)
24-
GetUserIDByNameFunc func(name string) (uuid.UUID, error)
25-
GetTopUsersFunc func(limit int) ([]types.User, error)
26-
GetAllUsersFunc func(excludeUserID *uuid.UUID) ([]types.User, error)
27-
UpdateDailyStepsFunc func(userID uuid.UUID, steps int) error
28-
GetUserStatisticsFunc func(userID uuid.UUID) ([]types.StepStatistic, error)
29-
GetSettingsByUserIDFunc func(userID uuid.UUID) (*types.Settings, error)
30-
CreateSettingsFunc func(settings types.Settings) error
31-
UpdateSettingsStepGoalFunc func(userID uuid.UUID, stepGoal int) error
32-
UpdateSettingsImageFunc func(userID uuid.UUID, imageID uuid.UUID) error
33-
UpdateStepGoalFunc func(userID uuid.UUID, stepGoal int) error
34-
UpdateImageFunc func(userID uuid.UUID, imageID uuid.UUID) error
35-
SaveImageFunc func(filename string, data []byte) (uuid.UUID, error)
36-
GetUserImageFunc func(userID uuid.UUID) (*types.UserImage, error)
37-
GetAllChallengesFunc func() ([]types.Challenge, error)
38-
AssignChallengesToUserFunc func(userID uuid.UUID, challenges []types.Challenge) error
39-
GetUserDailyChallengesFunc func(userID uuid.UUID) ([]types.Challenge, error)
40-
ResetDailyChallengesFunc func() error
41-
InsertChallengeFunc func(challenge types.Challenge) error
42-
CompleteChallengeFunc func(userID uuid.UUID, dto types.CompleteChallengesDTO) error
43-
IsNewDayForUserFunc func(userID uuid.UUID) (bool, error)
44-
CleanUpChallengesForUserFunc func(userID uuid.UUID) error
45-
AddFriendFunc func(userID, friendID uuid.UUID) error
46-
GetFriendsFunc func(userID uuid.UUID) ([]types.User, error)
47-
GetFriendsRankedByPointsFunc func(userID uuid.UUID) ([]types.User, error)
48-
DeleteFriendFunc func(userID, friendID uuid.UUID) error
49-
SaveRunFunc func(userID uuid.UUID, route string, duration string, distance float64) error
50-
GetAllRunsByUserFunc func(userID uuid.UUID) ([]types.RunDTO, error)
51-
DeleteRunFunc func(runID uuid.UUID) error
13+
ExecuteRawSQLFunc func(query string) (sql.Result, error)
14+
QueryRowFunc func(query string, args ...interface{}) *sql.Row
15+
HealthFunc func() map[string]string
16+
CloseFunc func() error
17+
SaveCredentialsFunc func(creds types.Credentials) error
18+
GetUserByEmailFunc func(email string) (types.Credentials, error)
19+
CheckEmailFunc func(email string) error
20+
SaveUserProfileFunc func(user types.User) error
21+
GetUserByIDFunc func(userID uuid.UUID) (types.User, error)
22+
UpdateRocketPointsFunc func(userID uuid.UUID, rocketPoints int) error
23+
GetRocketPointsByUserIDFunc func(userID uuid.UUID) (int, error)
24+
GetUserIDByNameFunc func(name string) (uuid.UUID, error)
25+
GetTopUsersFunc func(limit int) ([]types.User, error)
26+
GetAllUsersFunc func(excludeUserID *uuid.UUID) ([]types.User, error)
27+
UpdateDailyStepsFunc func(userID uuid.UUID, steps int) error
28+
GetUserStatisticsFunc func(userID uuid.UUID) ([]types.StepStatistic, error)
29+
GetSettingsByUserIDFunc func(userID uuid.UUID) (*types.Settings, error)
30+
CreateSettingsFunc func(settings types.Settings) error
31+
UpdateSettingsStepGoalFunc func(userID uuid.UUID, stepGoal int) error
32+
UpdateSettingsImageFunc func(userID uuid.UUID, imageID uuid.UUID) error
33+
UpdateStepGoalFunc func(userID uuid.UUID, stepGoal int) error
34+
UpdateImageFunc func(userID uuid.UUID, imageID uuid.UUID) error
35+
SaveImageFunc func(filename string, data []byte) (uuid.UUID, error)
36+
GetUserImageFunc func(userID uuid.UUID) (*types.UserImage, error)
37+
GetAllChallengesFunc func() ([]types.Challenge, error)
38+
AssignChallengesToUserFunc func(userID uuid.UUID, challenges []types.Challenge) error
39+
GetUserDailyChallengesFunc func(userID uuid.UUID) ([]types.Challenge, error)
40+
ResetDailyChallengesFunc func() error
41+
InsertChallengeFunc func(challenge types.Challenge) error
42+
CompleteChallengeFunc func(userID uuid.UUID, dto types.CompleteChallengesDTO) error
43+
IsNewDayForUserFunc func(userID uuid.UUID) (bool, error)
44+
CleanUpChallengesForUserFunc func(userID uuid.UUID) error
45+
AddFriendFunc func(userID, friendID uuid.UUID) error
46+
GetFriendsFunc func(userID uuid.UUID) ([]types.User, error)
47+
GetFriendsRankedByPointsFunc func(userID uuid.UUID) ([]types.User, error)
48+
DeleteFriendFunc func(userID, friendID uuid.UUID) error
49+
SaveRunFunc func(userID uuid.UUID, route string, duration string, distance float64) error
50+
GetAllRunsByUserFunc func(userID uuid.UUID) ([]types.RunDTO, error)
51+
DeleteRunFunc func(runID uuid.UUID) error
52+
GetChallengeByIDFunc func(challengeID uuid.UUID) (*types.Challenge, error)
53+
SaveActivityFunc func(userID uuid.UUID, message string) error
54+
GetActivitiesForUserAndFriendsFunc func(userID uuid.UUID) ([]types.ActivityWithUser, error)
5255
}
5356

5457
func (m *MockDB) ExecuteRawSQL(query string) (sql.Result, error) {
@@ -303,6 +306,27 @@ func (m *MockDB) GetAllUsers(userId *uuid.UUID) ([]types.User, error) {
303306
return nil, nil
304307
}
305308

309+
func (m *MockDB) GetChallengeByID(challengeID uuid.UUID) (*types.Challenge, error) {
310+
if m.GetChallengeByIDFunc != nil {
311+
return m.GetChallengeByIDFunc(challengeID)
312+
}
313+
return nil, nil
314+
}
315+
316+
func (m *MockDB) SaveActivity(userID uuid.UUID, message string) error {
317+
if m.SaveActivityFunc != nil {
318+
return m.SaveActivityFunc(userID, message)
319+
}
320+
return nil
321+
}
322+
323+
func (m *MockDB) GetActivitiesForUserAndFriends(userID uuid.UUID) ([]types.ActivityWithUser, error) {
324+
if m.GetActivitiesForUserAndFriendsFunc != nil {
325+
return m.GetActivitiesForUserAndFriendsFunc(userID)
326+
}
327+
return nil, nil
328+
}
329+
306330
func (m *MockDB) SaveRun(userID uuid.UUID, route string, duration string, distance float64) error {
307331
if m.SaveRunFunc != nil {
308332
return m.SaveRun(userID, route, duration, distance)

rocket-backend/integration-tests/server-tests/middleware_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ var _ = Describe("AuthMiddleware", func() {
4545
router.ServeHTTP(recorder, req)
4646

4747
Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
48-
Expect(recorder.Body.String()).To(ContainSubstring("Authorization header required"))
48+
Expect(recorder.Body.String()).To(ContainSubstring("Authorization header or jwt_token cookie required"))
4949
})
5050
})
5151

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package database
2+
3+
import (
4+
"fmt"
5+
"rocket-backend/internal/custom_error"
6+
"rocket-backend/internal/types"
7+
"rocket-backend/pkg/logger"
8+
"time"
9+
10+
"github.com/google/uuid"
11+
)
12+
13+
func (s *service) SaveActivity(userID uuid.UUID, message string) error {
14+
id := uuid.New()
15+
now := time.Now()
16+
17+
query := `
18+
INSERT INTO activities (id, user_id, time, message)
19+
VALUES ($1, $2, $3, $4)
20+
`
21+
_, err := s.db.Exec(query, id, userID, now, message)
22+
if err != nil {
23+
logger.Error(fmt.Sprintf("Failed to save activity: %v", err))
24+
return fmt.Errorf("%w: %v", custom_error.ErrFailedToSave, err)
25+
}
26+
return nil
27+
}
28+
29+
func (s *service) GetActivitiesForUserAndFriends(userID uuid.UUID) ([]types.ActivityWithUser, error) {
30+
query := `
31+
SELECT
32+
a.user_id,
33+
CASE WHEN a.user_id = $1 THEN 'You' ELSE u.username END AS name,
34+
a.time,
35+
a.message
36+
FROM activities a
37+
JOIN users u ON a.user_id = u.id
38+
WHERE
39+
(a.user_id = $1
40+
OR a.user_id IN (
41+
SELECT friend_id FROM friends WHERE user_id = $1
42+
))
43+
AND a.time::date = CURRENT_DATE
44+
ORDER BY a.time DESC
45+
`
46+
rows, err := s.db.Query(query, userID)
47+
if err != nil {
48+
logger.Error(fmt.Sprintf("Failed to fetch activities for user and friends: %v", err))
49+
return nil, custom_error.ErrFailedToRetrieveData
50+
}
51+
defer rows.Close()
52+
53+
var activities []types.ActivityWithUser
54+
for rows.Next() {
55+
var activity types.ActivityWithUser
56+
var uid uuid.UUID
57+
if err := rows.Scan(&uid, &activity.Name, &activity.Time, &activity.Message); err != nil {
58+
logger.Error(fmt.Sprintf("Failed to scan activity row: %v", err))
59+
return nil, custom_error.ErrDatabaseQuery
60+
}
61+
activities = append(activities, activity)
62+
}
63+
if err := rows.Err(); err != nil {
64+
logger.Error(fmt.Sprintf("Error iterating over activity rows: %v", err))
65+
return nil, custom_error.ErrDatabaseQuery
66+
}
67+
return activities, nil
68+
}

rocket-backend/internal/database/challenges_table.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,19 @@ func (s *service) CleanUpChallengesForUser(userID uuid.UUID) error {
219219

220220
return nil
221221
}
222+
223+
func (s *service) GetChallengeByID(challengeID uuid.UUID) (*types.Challenge, error) {
224+
query := `
225+
SELECT id, description AS text, points_reward AS points
226+
FROM challenges
227+
WHERE id = $1
228+
`
229+
var challenge types.Challenge
230+
err := s.db.QueryRow(query, challengeID).Scan(&challenge.ID, &challenge.Text, &challenge.Points)
231+
if err != nil {
232+
logger.Error("Failed to fetch challenge by ID", err)
233+
return nil, fmt.Errorf("failed to fetch challenge by ID: %v", err)
234+
}
235+
236+
return &challenge, nil
237+
}

rocket-backend/internal/database/database.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ type Service interface {
6868
CompleteChallenge(UserID uuid.UUID, dto types.CompleteChallengesDTO) error
6969
IsNewDayForUser(userID uuid.UUID) (bool, error)
7070
CleanUpChallengesForUser(userID uuid.UUID) error
71+
GetChallengeByID(challengeID uuid.UUID) (*types.Challenge, error)
7172

7273
// friends
7374
AddFriend(userID, friendID uuid.UUID) error
@@ -79,6 +80,10 @@ type Service interface {
7980
SaveRun(userID uuid.UUID, route string, duration string, distance float64) error
8081
GetAllRunsByUser(userID uuid.UUID) ([]types.RunDTO, error)
8182
DeleteRun(runID uuid.UUID) error
83+
84+
// activities
85+
SaveActivity(userID uuid.UUID, message string) error
86+
GetActivitiesForUserAndFriends(userID uuid.UUID) ([]types.ActivityWithUser, error)
8287
}
8388

8489
type service struct {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package server
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/gin-gonic/gin"
7+
"github.com/google/uuid"
8+
)
9+
10+
func (s *Server) GetActivityHandler(c *gin.Context) {
11+
userID, exists := c.Get("userID")
12+
if !exists {
13+
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
14+
return
15+
}
16+
17+
userUUID, err := uuid.Parse(userID.(string))
18+
if err != nil {
19+
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID format"})
20+
return
21+
}
22+
23+
activities, err := s.db.GetActivitiesForUserAndFriends(userUUID)
24+
if err != nil {
25+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch activities"})
26+
return
27+
}
28+
29+
user, err := s.db.GetUserByID(userUUID)
30+
if err != nil {
31+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch user data"})
32+
return
33+
}
34+
c.JSON(http.StatusOK, gin.H{"username": user.Username ,"activities": activities})
35+
}

rocket-backend/internal/server/challenge_handlers.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,15 @@ func (s *Server) CompleteChallengeHandler(c *gin.Context) {
8383
return
8484
}
8585

86+
// save activity
87+
challenge, err := s.db.GetChallengeByID(pointsDTO.ChallengeID)
88+
if err != nil {
89+
challenge.Text = "Unknown challenge"
90+
}
91+
92+
message := "Completed a daily challenge: " + challenge.Text
93+
err = s.db.SaveActivity(userUUID, message)
94+
95+
8696
c.JSON(http.StatusOK, gin.H{"message": "Challenge completed successfully"})
8797
}

rocket-backend/internal/server/middleware.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,20 @@ func (s *Server) AuthMiddleware() gin.HandlerFunc {
1616

1717
return func(c *gin.Context) {
1818
authHeader := c.GetHeader("Authorization")
19-
if authHeader == "" {
20-
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"})
21-
c.Abort()
22-
return
19+
var tokenString string
20+
21+
if authHeader != "" {
22+
tokenString = strings.TrimPrefix(authHeader, "Bearer ")
23+
} else {
24+
cookie, err := c.Cookie("jwt_token")
25+
if err != nil || cookie == "" {
26+
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header or jwt_token cookie required"})
27+
c.Abort()
28+
return
29+
}
30+
tokenString = cookie
2331
}
2432

25-
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
2633
token, err := authService.ParseToken(tokenString)
2734
if err != nil || !token.Valid {
2835
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})

rocket-backend/internal/server/public_handlers.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,8 @@ func (s *Server) RegisterHandler(c *gin.Context) {
123123

124124
c.JSON(http.StatusOK, gin.H{"message": "User registered successfully"})
125125
}
126+
127+
func (s *Server) LogoutHandler(c *gin.Context) {
128+
c.SetCookie("jwt_token", "", -1, "/", "", true, true)
129+
c.JSON(http.StatusOK, gin.H{"message": "Logged out successfully"})
130+
}

0 commit comments

Comments
 (0)