mirror of
https://github.com/kevin-DL/services.git
synced 2026-01-11 19:04:35 +00:00
fix the verification emails (#366)
* fix the verification emails * fix typo * switch to token only
This commit is contained in:
@@ -33,8 +33,11 @@ type pw struct {
|
||||
}
|
||||
|
||||
type verificationToken struct {
|
||||
UserID string `json:"userId"`
|
||||
Token string `json:"token"`
|
||||
// tenant id e.g micro_13425asdasa
|
||||
ID string `json:"id"`
|
||||
// user email
|
||||
Email string `json:"email"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type passwordResetCode struct {
|
||||
@@ -83,8 +86,11 @@ func (domain *Domain) SendEmail(fromName, toAddress, toUsername, subject, textCo
|
||||
from := mail.NewEmail(fromName, domain.fromEmail)
|
||||
to := mail.NewEmail(toUsername, toAddress)
|
||||
|
||||
uri := "https://user.m3o.com"
|
||||
query := "?token=" + token + "&redirectUrl=" + url.QueryEscape(redirctUrl) + "&failureRedirectUrl=" + url.QueryEscape(failureRedirectUrl)
|
||||
|
||||
// set the text content
|
||||
textContent = strings.Replace(textContent, "$micro_verification_link", "https://user.m3o.com?token="+token+"&redirectUrl="+url.QueryEscape(redirctUrl)+"&failureRedirectUrl="+url.QueryEscape(failureRedirectUrl), -1)
|
||||
textContent = strings.Replace(textContent, "$micro_verification_link", uri+query, -1)
|
||||
message := mail.NewSingleEmail(from, subject, to, textContent, "")
|
||||
|
||||
// send the email
|
||||
@@ -195,49 +201,55 @@ func (domain *Domain) DeleteSession(ctx context.Context, id string) error {
|
||||
}
|
||||
|
||||
// ReadToken returns the user id
|
||||
func (domain *Domain) ReadToken(ctx context.Context, email, token string) (string, error) {
|
||||
func (domain *Domain) ReadToken(ctx context.Context, token string) (string, string, error) {
|
||||
if token == "" {
|
||||
return "", errors.New("token id empty")
|
||||
return "", "", errors.New("token id empty")
|
||||
}
|
||||
|
||||
records, err := domain.store.Read(generateVerificationsTokenStoreKey(ctx, email, token))
|
||||
key := generateVerificationTokenStoreKey(token)
|
||||
|
||||
records, err := domain.store.Read(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
return "", errors.New("token not found")
|
||||
return "", "", errors.New("token not found")
|
||||
}
|
||||
|
||||
tk := &verificationToken{}
|
||||
err = json.Unmarshal(records[0].Value, tk)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
return tk.UserID, nil
|
||||
|
||||
// pass back tenant id
|
||||
return tk.ID, tk.Email, nil
|
||||
}
|
||||
|
||||
// CreateToken returns the created and saved token
|
||||
func (domain *Domain) CreateToken(ctx context.Context, email, token string) (string, error) {
|
||||
func (domain *Domain) CreateToken(ctx context.Context, email, token string) error {
|
||||
tk, err := json.Marshal(verificationToken{
|
||||
UserID: email,
|
||||
Token: token,
|
||||
ID: getTenantKey(ctx),
|
||||
Email: email,
|
||||
Token: token,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
|
||||
record := &store.Record{
|
||||
Key: generateVerificationsTokenStoreKey(ctx, email, token),
|
||||
Key: generateVerificationTokenStoreKey(token),
|
||||
Value: tk,
|
||||
}
|
||||
|
||||
err = domain.store.Write(record)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
|
||||
return token, err
|
||||
return err
|
||||
}
|
||||
|
||||
func (domain *Domain) ReadSession(ctx context.Context, id string) (*user.Session, error) {
|
||||
@@ -362,6 +374,38 @@ func (domain *Domain) Delete(ctx context.Context, userId string) error {
|
||||
return domain.batchDelete(keys)
|
||||
}
|
||||
|
||||
func (domain *Domain) MarkVerified(ctx context.Context, id, email string) error {
|
||||
key := generateAccountTenantEmailKey(id, email)
|
||||
|
||||
// get old information of the user
|
||||
user, err := domain.ReadUserByKey(ctx, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// mark as verified
|
||||
user.Verified = true
|
||||
user.Updated = time.Now().Unix()
|
||||
|
||||
val, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
records := []*store.Record{
|
||||
{Key: generateAccountTenantKey(id, user.Id), Value: val},
|
||||
{Key: generateAccountTenantUsernameKey(id, user.Username), Value: val},
|
||||
{Key: generateAccountTenantEmailKey(id, user.Email), Value: val},
|
||||
}
|
||||
|
||||
// update
|
||||
if err := domain.batchWrite(records); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (domain *Domain) Update(ctx context.Context, user *user.Account) error {
|
||||
// get old information of the user
|
||||
old, err := domain.Read(ctx, user.Id)
|
||||
@@ -405,8 +449,8 @@ func (domain *Domain) Update(ctx context.Context, user *user.Account) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// readUserByKey read user account in store by key
|
||||
func (domain *Domain) readUserByKey(ctx context.Context, key string) (*user.Account, error) {
|
||||
// ReadUserByKey read user account in store by key
|
||||
func (domain *Domain) ReadUserByKey(ctx context.Context, key string) (*user.Account, error) {
|
||||
var result = &user.Account{}
|
||||
records, err := domain.store.Read(key)
|
||||
if err != nil {
|
||||
@@ -422,15 +466,15 @@ func (domain *Domain) readUserByKey(ctx context.Context, key string) (*user.Acco
|
||||
}
|
||||
|
||||
func (domain *Domain) Read(ctx context.Context, userId string) (*user.Account, error) {
|
||||
return domain.readUserByKey(ctx, generateAccountStoreKey(ctx, userId))
|
||||
return domain.ReadUserByKey(ctx, generateAccountStoreKey(ctx, userId))
|
||||
}
|
||||
|
||||
func (domain *Domain) SearchByUsername(ctx context.Context, username string) (*user.Account, error) {
|
||||
return domain.readUserByKey(ctx, generateAccountUsernameStoreKey(ctx, username))
|
||||
return domain.ReadUserByKey(ctx, generateAccountUsernameStoreKey(ctx, username))
|
||||
}
|
||||
|
||||
func (domain *Domain) SearchByEmail(ctx context.Context, email string) (*user.Account, error) {
|
||||
return domain.readUserByKey(ctx, generateAccountEmailStoreKey(ctx, email))
|
||||
return domain.ReadUserByKey(ctx, generateAccountEmailStoreKey(ctx, email))
|
||||
}
|
||||
|
||||
func (domain *Domain) Search(ctx context.Context, username, email string) ([]*user.Account, error) {
|
||||
|
||||
@@ -17,12 +17,31 @@ func getStoreKeyPrefix(ctx context.Context) string {
|
||||
return getStoreKeyPrefixForTenent(tenantId)
|
||||
}
|
||||
|
||||
func getStoreKeyPrefixForTenent(tenantID string) string {
|
||||
tid := strings.Replace(strings.Replace(tenantID, "/", "_", -1), "-", "_", -1)
|
||||
func getTenantKey(ctx context.Context) string {
|
||||
tenantId, ok := tenant.FromContext(ctx)
|
||||
if !ok {
|
||||
tenantId = "micro"
|
||||
}
|
||||
|
||||
return strings.Replace(strings.Replace(tenantId, "/", "_", -1), "-", "_", -1)
|
||||
}
|
||||
|
||||
func getStoreKeyPrefixForTenent(tenantId string) string {
|
||||
tid := strings.Replace(strings.Replace(tenantId, "/", "_", -1), "-", "_", -1)
|
||||
|
||||
return fmt.Sprintf("user/%s/", tid)
|
||||
}
|
||||
|
||||
func generateAccountTenantKey(tenantId, userId string) string {
|
||||
return fmt.Sprintf("%saccount/id/%s", getStoreKeyPrefixForTenent(tenantId), userId)
|
||||
}
|
||||
func generateAccountTenantEmailKey(tenantId, email string) string {
|
||||
return fmt.Sprintf("%sacccount/email/%s", getStoreKeyPrefixForTenent(tenantId), email)
|
||||
}
|
||||
func generateAccountTenantUsernameKey(tenantId, username string) string {
|
||||
return fmt.Sprintf("%saccount/username/%s", getStoreKeyPrefixForTenent(tenantId), username)
|
||||
}
|
||||
|
||||
func generateAccountStoreKey(ctx context.Context, userId string) string {
|
||||
return fmt.Sprintf("%saccount/id/%s", getStoreKeyPrefix(ctx), userId)
|
||||
}
|
||||
@@ -47,6 +66,6 @@ func generateSessionStoreKey(ctx context.Context, sessionId string) string {
|
||||
return fmt.Sprintf("%ssession/%s", getStoreKeyPrefix(ctx), sessionId)
|
||||
}
|
||||
|
||||
func generateVerificationsTokenStoreKey(ctx context.Context, userId, token string) string {
|
||||
return fmt.Sprintf("%sverification-token/%s-%s", getStoreKeyPrefix(ctx), userId, token)
|
||||
func generateVerificationTokenStoreKey(token string) string {
|
||||
return fmt.Sprintf("user/verification-token/%s", token)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user