-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of https://github.com/SpeedReach/monify
modify the function "createGroupMember()": remove memberId
- Loading branch information
Showing
6 changed files
with
139 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,82 @@ | ||
package group | ||
|
||
import ( | ||
"context" | ||
"database/sql" | ||
"github.com/google/uuid" | ||
"go.uber.org/zap" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
"math" | ||
"math/rand" | ||
"monify/internal/middlewares" | ||
monify "monify/protobuf" | ||
"time" | ||
) | ||
|
||
const ( | ||
inviteCodeChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" | ||
timeDeterLength = 4 | ||
randomLength = 2 | ||
inviteCodeLength = timeDeterLength + randomLength | ||
expiresInterval = int64(time.Minute * 10) | ||
) | ||
|
||
func checkPermission(ctx context.Context, db *sql.DB, groupId uuid.UUID, userId uuid.UUID) (bool, error) { | ||
var count int | ||
err := db.QueryRow(` | ||
SELECT COUNT(*) FROM group_member WHERE group_id = $1 AND user_id = $2 | ||
`, groupId, userId).Scan(&count) | ||
if err != nil { | ||
return false, err | ||
} | ||
return count > 0, nil | ||
} | ||
|
||
func (s Service) GenerateInviteCode(ctx context.Context, req *monify.GenerateInviteCodeRequest) (*monify.GenerateInviteCodeResponse, error) { | ||
userId, ok := ctx.Value(middlewares.UserIdContextKey{}).(uuid.UUID) | ||
db := ctx.Value(middlewares.StorageContextKey{}).(*sql.DB) | ||
logger := ctx.Value(middlewares.LoggerContextKey{}).(*zap.Logger) | ||
if !ok { | ||
return nil, status.Error(codes.Unauthenticated, "Unauthorized.") | ||
} | ||
groupId, err := uuid.Parse(req.GroupId) | ||
if err != nil { | ||
return nil, status.Error(codes.InvalidArgument, "Invalid group ID") | ||
} | ||
hasPerm, err := checkPermission(ctx, db, groupId, userId) | ||
if err != nil { | ||
logger.Error("Failed to check permission", zap.Error(err)) | ||
return nil, status.Error(codes.Internal, "Internal") | ||
} | ||
if !hasPerm { | ||
return nil, status.Error(codes.PermissionDenied, "Permission denied") | ||
} | ||
inviteCode := generateInviteCode() | ||
_, err = db.Exec(` | ||
INSERT INTO invite_code (group_id, code) VALUES ($1, $2) | ||
`, groupId, inviteCode) | ||
return nil, err | ||
} | ||
|
||
func indexToChar(index int) byte { | ||
return inviteCodeChars[index] | ||
} | ||
func generateInviteCode() string { | ||
charsCount := len(inviteCodeChars) | ||
seed := time.Now().UnixMilli() % expiresInterval | ||
inviteCodeRange := int(math.Pow(float64(charsCount), timeDeterLength)) | ||
code := int(seed) % inviteCodeRange | ||
inviteCode := "" | ||
|
||
for i := 0; i < timeDeterLength; i++ { | ||
index := code % charsCount | ||
code /= charsCount | ||
inviteCode += string(indexToChar(index)) | ||
} | ||
|
||
for i := 0; i < randomLength; i++ { | ||
inviteCode += string(indexToChar(rand.Int() % charsCount)) | ||
} | ||
return inviteCode | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package group | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestIndexToChar(t *testing.T) { | ||
assert.Equal(t, byte('0'), indexToChar(0), "Expected '0' for index 0") | ||
assert.Equal(t, byte('1'), indexToChar(1), "Expected '1' for index 1") | ||
assert.Equal(t, byte('2'), indexToChar(2), "Expected '2' for index 2") | ||
assert.Equal(t, byte('8'), indexToChar(8), "Expected '8' for index 8") | ||
assert.Equal(t, byte('a'), indexToChar(10), "Expected 'a' for index 10") | ||
assert.Equal(t, byte('b'), indexToChar(11), "Expected 'b' for index 11") | ||
assert.Equal(t, byte('z'), indexToChar(35), "Expected 'z' for index 35") | ||
assert.Equal(t, byte('A'), indexToChar(36), "Expected 'A' for index 36") | ||
assert.Equal(t, byte('B'), indexToChar(37), "Expected 'B' for index 37") | ||
assert.Equal(t, byte('Z'), indexToChar(61), "Expected 'Z' for index 61") | ||
} | ||
|
||
func TestGenerateInviteCodeUniqueness(t *testing.T) { | ||
inviteCode := generateInviteCode() | ||
println(inviteCode) | ||
assert.Len(t, inviteCode, inviteCodeLength, "Expected invite code to be 6 characters long") | ||
for _, char := range inviteCode { | ||
assert.True(t, char >= '0' && char <= '9' || char >= 'a' && char <= 'z' || char >= 'A' && char <= 'Z', "Expected invite code to contain only alphanumeric characters") | ||
} | ||
time.Sleep(time.Millisecond) | ||
inviteCode2 := generateInviteCode() | ||
assert.NotEqual(t, inviteCode, inviteCode2, "Expected two different invite codes") | ||
} | ||
|
||
func TestGenerateInviteCodeRandomness(t *testing.T) { | ||
//try to generate 1000 invite codes and check if 990 of them are unique | ||
failCount := 0 | ||
tries := 1000 | ||
for i := 0; i < tries; i++ { | ||
if generateInviteCode() == generateInviteCode() { | ||
failCount++ | ||
} | ||
} | ||
println(failCount) | ||
assert.LessOrEqual(t, failCount, 10, "Expected 990 out of 1000 invite codes to be unique") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters