web/satellite: auth graphql api replaced with REST API (#3396)

This commit is contained in:
Nikolai Siedov 2019-10-29 16:24:16 +02:00 committed by GitHub
parent b0a9438137
commit 6354b38849
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 246 additions and 254 deletions

View File

@ -62,17 +62,13 @@ func (a *Auth) Token(w http.ResponseWriter, r *http.Request) {
return
}
var tokenResponse struct {
Token string `json:"token"`
}
tokenResponse.Token, err = a.service.Token(ctx, tokenRequest.Email, tokenRequest.Password)
token, err := a.service.Token(ctx, tokenRequest.Email, tokenRequest.Password)
if err != nil {
a.serveJSONError(w, http.StatusUnauthorized, err)
return
}
err = json.NewEncoder(w).Encode(tokenResponse)
err = json.NewEncoder(w).Encode(token)
if err != nil {
a.log.Error("token handler could not encode token response", zap.Error(ErrAuthAPI.Wrap(err)))
return
@ -85,25 +81,39 @@ func (a *Auth) Register(w http.ResponseWriter, r *http.Request) {
var err error
defer mon.Task()(&ctx)(&err)
var request struct {
UserInfo console.CreateUser `json:"userInfo"`
SecretInput string `json:"secret"`
ReferrerUserID string `json:"referrerUserID"`
var registerData struct {
FullName string `json:"fullName"`
ShortName string `json:"shortName"`
Email string `json:"email"`
PartnerID string `json:"partnerId"`
Password string `json:"password"`
SecretInput string `json:"secret"`
ReferrerUserID string `json:"referrerUserID"`
}
err = json.NewDecoder(r.Body).Decode(&request)
err = json.NewDecoder(r.Body).Decode(&registerData)
if err != nil {
a.serveJSONError(w, http.StatusBadRequest, err)
return
}
secret, err := console.RegistrationSecretFromBase64(request.SecretInput)
secret, err := console.RegistrationSecretFromBase64(registerData.SecretInput)
if err != nil {
a.serveJSONError(w, http.StatusBadRequest, err)
return
}
user, err := a.service.CreateUser(ctx, request.UserInfo, secret, request.ReferrerUserID)
user, err := a.service.CreateUser(ctx,
console.CreateUser{
FullName: registerData.FullName,
ShortName: registerData.ShortName,
Email: registerData.Email,
PartnerID: registerData.PartnerID,
Password: registerData.Password,
},
secret,
registerData.ReferrerUserID,
)
if err != nil {
a.serveJSONError(w, http.StatusInternalServerError, err)
return
@ -115,7 +125,7 @@ func (a *Auth) Register(w http.ResponseWriter, r *http.Request) {
return
}
link := a.ExternalAddress + consoleql.ActivationPath + token
link := a.ExternalAddress + "activation/?token=" + token
userName := user.ShortName
if user.ShortName == "" {
userName = user.FullName
@ -137,8 +147,8 @@ func (a *Auth) Register(w http.ResponseWriter, r *http.Request) {
}
}
// Update updates user's full name and short name.
func (a *Auth) Update(w http.ResponseWriter, r *http.Request) {
// UpdateAccount updates user's full name and short name.
func (a *Auth) UpdateAccount(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
@ -160,8 +170,8 @@ func (a *Auth) Update(w http.ResponseWriter, r *http.Request) {
}
}
// Get gets authorized user and take it's params.
func (a *Auth) Get(w http.ResponseWriter, r *http.Request) {
// GetAccount gets authorized user and take it's params.
func (a *Auth) GetAccount(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
@ -193,23 +203,23 @@ func (a *Auth) Get(w http.ResponseWriter, r *http.Request) {
}
}
// Delete - authorizes user and deletes account by password.
func (a *Auth) Delete(w http.ResponseWriter, r *http.Request) {
// DeleteAccount - authorizes user and deletes account by password.
func (a *Auth) DeleteAccount(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
var request struct {
var deleteRequest struct {
Password string `json:"password"`
}
err = json.NewDecoder(r.Body).Decode(&request)
err = json.NewDecoder(r.Body).Decode(&deleteRequest)
if err != nil {
a.serveJSONError(w, http.StatusBadRequest, err)
return
}
err = a.service.DeleteAccount(ctx, request.Password)
err = a.service.DeleteAccount(ctx, deleteRequest.Password)
if err != nil {
if console.ErrUnauthorized.Has(err) {
a.serveJSONError(w, http.StatusUnauthorized, err)
@ -276,8 +286,8 @@ func (a *Auth) ForgotPassword(w http.ResponseWriter, r *http.Request) {
return
}
passwordRecoveryLink := a.ExternalAddress + consoleql.CancelPasswordRecoveryPath + recoveryToken
cancelPasswordRecoveryLink := a.ExternalAddress + consoleql.CancelPasswordRecoveryPath + recoveryToken
passwordRecoveryLink := a.ExternalAddress + "password-recovery/?token=" + recoveryToken
cancelPasswordRecoveryLink := a.ExternalAddress + "cancel-password-recovery/?token=" + recoveryToken
userName := user.ShortName
if user.ShortName == "" {
userName = user.FullName
@ -309,13 +319,13 @@ func (a *Auth) ResendEmail(w http.ResponseWriter, r *http.Request) {
defer mon.Task()(&ctx)(&err)
params := mux.Vars(r)
val, ok := params["id"]
id, ok := params["id"]
if !ok {
a.serveJSONError(w, http.StatusBadRequest, errs.New("id expected"))
return
}
userID, err := uuid.Parse(val)
userID, err := uuid.Parse(id)
if err != nil {
a.serveJSONError(w, http.StatusBadRequest, err)
return
@ -333,7 +343,7 @@ func (a *Auth) ResendEmail(w http.ResponseWriter, r *http.Request) {
return
}
link := a.ExternalAddress + consoleql.ActivationPath + token
link := a.ExternalAddress + "activation/?token=" + token
userName := user.ShortName
if user.ShortName == "" {
userName = user.FullName

View File

@ -79,13 +79,11 @@ func TestGrapqhlMutation(t *testing.T) {
require.NoError(t, err)
createUser := console.CreateUser{
UserInfo: console.UserInfo{
FullName: "John Roll",
ShortName: "Roll",
Email: "test@mail.test",
PartnerID: "120bf202-8252-437e-ac12-0e364bee852e",
},
Password: "123a123",
FullName: "John Roll",
ShortName: "Roll",
Email: "test@mail.test",
PartnerID: "120bf202-8252-437e-ac12-0e364bee852e",
Password: "123a123",
}
refUserID := ""
@ -126,13 +124,11 @@ func TestGrapqhlMutation(t *testing.T) {
t.Run("Create user mutation with partner id", func(t *testing.T) {
newUser := console.CreateUser{
UserInfo: console.UserInfo{
FullName: "Green Mickey",
ShortName: "Green",
Email: "u1@mail.test",
PartnerID: "120bf202-8252-437e-ac12-0e364bee852e",
},
Password: "123a123",
FullName: "Green Mickey",
ShortName: "Green",
Email: "u1@mail.test",
PartnerID: "120bf202-8252-437e-ac12-0e364bee852e",
Password: "123a123",
}
require.NoError(t, err)
@ -178,13 +174,11 @@ func TestGrapqhlMutation(t *testing.T) {
t.Run("Create user mutation without partner id", func(t *testing.T) {
newUser := console.CreateUser{
UserInfo: console.UserInfo{
FullName: "Red Mickey",
ShortName: "Red",
Email: "u2@mail.test",
PartnerID: "",
},
Password: "123a123",
FullName: "Red Mickey",
ShortName: "Red",
Email: "u2@mail.test",
PartnerID: "",
Password: "123a123",
}
require.NoError(t, err)
@ -243,24 +237,6 @@ func TestGrapqhlMutation(t *testing.T) {
return result.Data
}
t.Run("Update account mutation email only", func(t *testing.T) {
email := "new@mail.test"
query := fmt.Sprintf(
"mutation {updateAccount(input:{email:\"%s\"}){id,email,fullName,shortName,createdAt}}",
email,
)
result := testQuery(t, query)
data := result.(map[string]interface{})
user := data[consoleql.UpdateAccountMutation].(map[string]interface{})
assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID])
assert.Equal(t, email, user[consoleql.FieldEmail])
assert.Equal(t, rootUser.FullName, user[consoleql.FieldFullName])
assert.Equal(t, rootUser.ShortName, user[consoleql.FieldShortName])
})
t.Run("Update account mutation fullName only", func(t *testing.T) {
fullName := "George"
query := fmt.Sprintf(
@ -298,13 +274,11 @@ func TestGrapqhlMutation(t *testing.T) {
})
t.Run("Update account mutation all info", func(t *testing.T) {
email := "test@newmail.com"
fullName := "Fill Goal"
shortName := "Goal"
query := fmt.Sprintf(
"mutation {updateAccount(input:{email:\"%s\",fullName:\"%s\",shortName:\"%s\"}){id,email,fullName,shortName,createdAt}}",
email,
"mutation {updateAccount(input:{,fullName:\"%s\",shortName:\"%s\"}){id,fullName,shortName,createdAt}}",
fullName,
shortName,
)
@ -315,7 +289,6 @@ func TestGrapqhlMutation(t *testing.T) {
user := data[consoleql.UpdateAccountMutation].(map[string]interface{})
assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID])
assert.Equal(t, email, user[consoleql.FieldEmail])
assert.Equal(t, fullName, user[consoleql.FieldFullName])
assert.Equal(t, shortName, user[consoleql.FieldShortName])
@ -421,10 +394,8 @@ func TestGrapqhlMutation(t *testing.T) {
require.NoError(t, err)
user1, err := service.CreateUser(authCtx, console.CreateUser{
UserInfo: console.UserInfo{
FullName: "User1",
Email: "u1@mail.test",
},
FullName: "User1",
Email: "u1@mail.test",
Password: "123a123",
}, regTokenUser1.Secret, refUserID)
require.NoError(t, err)
@ -447,10 +418,8 @@ func TestGrapqhlMutation(t *testing.T) {
require.NoError(t, err)
user2, err := service.CreateUser(authCtx, console.CreateUser{
UserInfo: console.UserInfo{
FullName: "User1",
Email: "u2@mail.test",
},
FullName: "User1",
Email: "u2@mail.test",
Password: "123a123",
}, regTokenUser2.Secret, refUserID)
require.NoError(t, err)

View File

@ -66,12 +66,10 @@ func TestGraphqlQuery(t *testing.T) {
require.NoError(t, err)
createUser := console.CreateUser{
UserInfo: console.UserInfo{
FullName: "John",
ShortName: "",
Email: "mtest@mail.test",
},
Password: "123a123",
FullName: "John",
ShortName: "",
Email: "mtest@mail.test",
Password: "123a123",
}
refUserID := ""
@ -189,12 +187,10 @@ func TestGraphqlQuery(t *testing.T) {
require.NoError(t, err)
user1, err := service.CreateUser(authCtx, console.CreateUser{
UserInfo: console.UserInfo{
FullName: "Mickey Last",
ShortName: "Last",
Email: "muu1@mail.test",
},
Password: "123a123",
FullName: "Mickey Last",
ShortName: "Last",
Password: "123a123",
Email: "muu1@mail.test",
}, regTokenUser1.Secret, refUserID)
require.NoError(t, err)
@ -215,12 +211,10 @@ func TestGraphqlQuery(t *testing.T) {
require.NoError(t, err)
user2, err := service.CreateUser(authCtx, console.CreateUser{
UserInfo: console.UserInfo{
FullName: "Dubas Name",
ShortName: "Name",
Email: "muu2@mail.test",
},
Password: "123a123",
FullName: "Dubas Name",
ShortName: "Name",
Email: "muu2@mail.test",
Password: "123a123",
}, regTokenUser2.Secret, refUserID)
require.NoError(t, err)
@ -437,12 +431,10 @@ func TestGraphqlQuery(t *testing.T) {
regToken, err := service.CreateRegToken(ctx, 2)
require.NoError(t, err)
user, err := service.CreateUser(authCtx, console.CreateUser{
UserInfo: console.UserInfo{
FullName: "Example User",
ShortName: "Example",
Email: "user@mail.test",
},
Password: "123a123",
FullName: "Example User",
ShortName: "Example",
Email: "user@mail.test",
Password: "123a123",
}, regToken.Secret, refUserID)
require.NoError(t, err)
@ -477,12 +469,10 @@ func TestGraphqlQuery(t *testing.T) {
regToken, err := service.CreateRegToken(ctx, 2)
require.NoError(t, err)
user, err := service.CreateUser(authCtx, console.CreateUser{
UserInfo: console.UserInfo{
FullName: "Example User",
ShortName: "Example",
Email: "user1@mail.test",
},
Password: "123a123",
FullName: "Example User",
ShortName: "Example",
Email: "user1@mail.test",
Password: "123a123",
}, regToken.Secret, refUserID)
require.NoError(t, err)

View File

@ -5,7 +5,6 @@ package consoleql
import (
"github.com/graphql-go/graphql"
"github.com/skyrings/skyring-common/tools/uuid"
"storj.io/storj/satellite/console"
)
@ -88,31 +87,21 @@ func graphqlUserInput() *graphql.InputObject {
})
}
// fromMapUserInfo creates UserInput from input args
func fromMapUserInfo(args map[string]interface{}) (user console.UserInfo) {
func fromMapCreateUser(args map[string]interface{}) (user console.CreateUser) {
user.Email, _ = args[FieldEmail].(string)
user.FullName, _ = args[FieldFullName].(string)
user.ShortName, _ = args[FieldShortName].(string)
user.PartnerID, _ = args[FieldPartnerID].(string)
return
}
func fromMapCreateUser(args map[string]interface{}) (user console.CreateUser) {
user.UserInfo = fromMapUserInfo(args)
user.Password, _ = args[FieldPassword].(string)
user.PartnerID, _ = args[FieldPartnerID].(string)
return
}
// fillUserInfo fills satellite.UserInfo from satellite.User and input args
func fillUserInfo(user *console.User, args map[string]interface{}) console.UserInfo {
info := console.UserInfo{
Email: user.Email,
FullName: user.FullName,
ShortName: user.ShortName,
}
if !user.PartnerID.IsZero() {
info.PartnerID = user.PartnerID.String()
}
for fieldName, fieldValue := range args {
value, ok := fieldValue.(string)
@ -121,21 +110,12 @@ func fillUserInfo(user *console.User, args map[string]interface{}) console.UserI
}
switch fieldName {
case FieldEmail:
info.Email = value
user.Email = value
case FieldFullName:
info.FullName = value
user.FullName = value
case FieldShortName:
info.ShortName = value
user.ShortName = value
case FieldPartnerID:
info.PartnerID = value
partnerID, err := uuid.Parse(value)
if err == nil {
user.PartnerID = *partnerID
}
}
}

View File

@ -120,19 +120,18 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, mail
router.HandleFunc("/api/v0/graphql", server.grapqlHandler)
router.HandleFunc("/registrationToken/", server.createRegistrationTokenHandler)
router.HandleFunc("/robots.txt", server.seoHandler)
router.HandleFunc("/satelliteName", server.satelliteNameHandler).Methods(http.MethodGet)
router.HandleFunc("/satellite-name", server.satelliteNameHandler).Methods(http.MethodGet)
authController := consoleapi.NewAuth(logger, service, mailService, config.ExternalAddress, config.LetUsKnowURL, config.TermsAndConditionsURL, config.ContactInfoURL)
authController := consoleapi.NewAuth(logger, service, mailService, server.config.ExternalAddress, config.LetUsKnowURL, config.TermsAndConditionsURL, config.ContactInfoURL)
authRouter := router.PathPrefix("/api/v0/auth").Subrouter()
authRouter.Handle("/account", server.withAuth(http.HandlerFunc(authController.GetAccount))).Methods(http.MethodGet)
authRouter.Handle("/account", server.withAuth(http.HandlerFunc(authController.UpdateAccount))).Methods(http.MethodPatch)
authRouter.Handle("/account/change-password", server.withAuth(http.HandlerFunc(authController.ChangePassword))).Methods(http.MethodPost)
authRouter.Handle("/account/delete", server.withAuth(http.HandlerFunc(authController.DeleteAccount))).Methods(http.MethodPost)
authRouter.HandleFunc("/token", authController.Token).Methods(http.MethodPost)
authRouter.HandleFunc("/register", authController.Register).Methods(http.MethodPost)
authRouter.Handle("/changePassword", server.withAuth(http.HandlerFunc(authController.ChangePassword))).Methods(http.MethodPost)
authRouter.Handle("/delete", server.withAuth(http.HandlerFunc(authController.Delete))).Methods(http.MethodDelete)
authRouter.Handle("/", server.withAuth(http.HandlerFunc(authController.Get))).Methods(http.MethodGet)
authRouter.Handle("/update", server.withAuth(http.HandlerFunc(authController.Update))).Methods(http.MethodPut)
authRouter.HandleFunc("/changePassword", authController.ChangePassword).Methods(http.MethodPost)
authRouter.HandleFunc("/forgotPassword", authController.ForgotPassword).Methods(http.MethodPost)
authRouter.HandleFunc("/resendEmail", authController.ResendEmail).Methods(http.MethodPost)
authRouter.HandleFunc("/forgot-password/{email}", authController.ForgotPassword).Methods(http.MethodPost)
authRouter.HandleFunc("/resend-email/{id}", authController.ResendEmail).Methods(http.MethodPost)
paymentController := consoleapi.NewPayments(logger, service)
paymentsRouter := router.PathPrefix("/api/v0/payments").Subrouter()

View File

@ -31,21 +31,15 @@ type Users interface {
type UserInfo struct {
FullName string `json:"fullName"`
ShortName string `json:"shortName"`
Email string `json:"email"`
PartnerID string `json:"partnerId"`
}
// IsValid checks UserInfo validity and returns error describing whats wrong.
func (user *UserInfo) IsValid() error {
var errs validationErrors
// validate email
_, err := mail.ParseAddress(user.Email)
errs.AddWrap(err)
// validate fullName
if user.FullName == "" {
errs.Add("fullName can't be empty")
if err := validateFullName(user.FullName); err != nil {
errs.AddWrap(err)
}
return errs.Combine()
@ -53,17 +47,24 @@ func (user *UserInfo) IsValid() error {
// CreateUser struct holds info for User creation.
type CreateUser struct {
UserInfo
Password string `json:"password"`
FullName string `json:"fullName"`
ShortName string `json:"shortName"`
Email string `json:"email"`
PartnerID string `json:"partnerId"`
Password string `json:"password"`
}
// IsValid checks CreateUser validity and returns error describing whats wrong.
func (user *CreateUser) IsValid() error {
var errs validationErrors
errs.AddWrap(user.UserInfo.IsValid())
errs.AddWrap(validateFullName(user.FullName))
errs.AddWrap(validatePassword(user.Password))
// validate email
_, err := mail.ParseAddress(user.Email)
errs.AddWrap(err)
if user.PartnerID != "" {
_, err := uuid.Parse(user.PartnerID)
if err != nil {

View File

@ -42,3 +42,12 @@ func validatePassword(pass string) error {
return errs.Combine()
}
// validateFullName validates full name.
func validateFullName(name string) error {
if name == "" {
return errs.New("full name can not be empty")
}
return nil
}

View File

@ -54,6 +54,9 @@ func (clicker *LinkClicker) SendEmail(ctx context.Context, msg *post.Message) (e
var sendError error
for _, link := range links {
response, err := http.Get(link)
if err != nil {
continue
}
sendError = errs.Combine(sendError, err, response.Body.Close())
}

View File

@ -1,14 +1,17 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
import { BaseGql } from '@/api/baseGql';
import { User } from '@/types/users';
import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized';
import { UpdatedUser, User } from '@/types/users';
import { HttpClient } from '@/utils/httpClient';
/**
* AuthApiGql is a graphql implementation of Auth API.
* AuthHttpApi is a console Auth API.
* Exposes all auth-related functionality
*/
export class AuthApi extends BaseGql {
export class AuthHttpApi {
private readonly http: HttpClient = new HttpClient();
private readonly ROOT_PATH: string = '/api/v0/auth';
/**
* Used to resend an registration confirmation email
*
@ -16,16 +19,13 @@ export class AuthApi extends BaseGql {
* @throws Error
*/
public async resendEmail(userId: string): Promise<void> {
const query =
`query ($userId: String!){
resendAccountActivationEmail(id: $userId)
}`;
const path = `${this.ROOT_PATH}/resend-email/${userId}`;
const response = await this.http.post(path, userId, false);
if (response.ok) {
return;
}
const variables = {
userId,
};
await this.query(query, variables);
throw new Error('can not resend Email');
}
/**
@ -36,21 +36,17 @@ export class AuthApi extends BaseGql {
* @throws Error
*/
public async token(email: string, password: string): Promise<string> {
const query =
` query ($email: String!, $password: String!) {
token(email: $email, password: $password) {
token
}
}`;
const variables = {
email,
password,
const path = `${this.ROOT_PATH}/token`;
const body = {
email: email,
password: password,
};
const response = await this.http.post(path, JSON.stringify(body), false);
if (response.ok) {
return await response.json();
}
const response = await this.query(query, variables);
return response.data.token.token;
throw new Error('can not receive authentication token');
}
/**
@ -60,16 +56,48 @@ export class AuthApi extends BaseGql {
* @throws Error
*/
public async forgotPassword(email: string): Promise<void> {
const query =
`query($email: String!) {
forgotPassword(email: $email)
}`;
const path = `${this.ROOT_PATH}/forgot-password/${email}`;
const response = await this.http.post(path, email, false);
if (response.ok) {
return;
}
const variables = {
email,
throw new Error('can not resend password');
}
/**
* Used to update user full and short name
*
* @param userInfo - full name and short name of the user
* @throws Error
*/
public async update(userInfo: UpdatedUser): Promise<void> {
const path = `${this.ROOT_PATH}/account`;
const body = {
fullName: userInfo.fullName,
shortName: userInfo.shortName,
};
const response = await this.http.patch(path, JSON.stringify(body), true);
if (response.ok) {
return;
}
await this.query(query, variables);
throw new Error('can not update user data');
}
/**
* Used to get user data
*
* @throws Error
*/
public async get(): Promise<User> {
const path = `${this.ROOT_PATH}/account`;
const response = await this.http.get(path, true);
if (response.ok) {
return await response.json();
}
throw new Error('can not get user data');
}
/**
@ -80,22 +108,21 @@ export class AuthApi extends BaseGql {
* @throws Error
*/
public async changePassword(password: string, newPassword: string): Promise<void> {
const query =
`mutation($password: String!, $newPassword: String!) {
changePassword (
password: $password,
newPassword: $newPassword
) {
email
}
}`;
const variables = {
password,
newPassword,
const path = `${this.ROOT_PATH}/account/change-password`;
const body = {
password: password,
newPassword: newPassword,
};
const response = await this.http.post(path, JSON.stringify(body), true);
if (response.ok) {
return;
}
await this.mutate(query, variables);
if (response.status === 401) {
throw new ErrorUnauthorized();
}
throw new Error('can not change password');
}
/**
@ -105,59 +132,49 @@ export class AuthApi extends BaseGql {
* @throws Error
*/
public async delete(password: string): Promise<void> {
const query =
`mutation ($password: String!){
deleteAccount(password: $password) {
email
}
}`;
const variables = {
password,
const path = `${this.ROOT_PATH}/account/delete`;
const body = {
password: password,
};
const response = await this.http.post(path, JSON.stringify(body), true);
if (response.ok) {
return;
}
await this.mutate(query, variables);
if (response.status === 401) {
throw new ErrorUnauthorized();
}
throw new Error('can not delete user');
}
// TODO: remove secret after Vanguard release
/**
* Used to create account
* Used to register account
*
* @param user - stores user information
* @param secret - registration token used in Vanguard release
* @param refUserId - referral id to participate in bonus program
* @param referrerUserId - referral id to participate in bonus program
* @returns id of created user
* @throws Error
*/
public async create(user: User, password: string, secret: string, referrerUserId: string = ''): Promise<string> {
const query =
`mutation($email: String!, $password: String!, $fullName: String!, $shortName: String!,
$partnerID: String!, $referrerUserId: String!, $secret: String!) {
createUser(
input: {
email: $email,
password: $password,
fullName: $fullName,
shortName: $shortName,
partnerId: $partnerID
},
referrerUserId: $referrerUserId,
secret: $secret,
) {email, id}
}`;
const variables = {
email: user.email,
public async register(user: {fullName: string; shortName: string; email: string; partnerId: string; password: string}, secret: string, referrerUserId: string): Promise<string> {
const path = `${this.ROOT_PATH}/register`;
const body = {
secret: secret,
referrerUserId: referrerUserId ? referrerUserId : '',
password: user.password,
fullName: user.fullName,
shortName: user.shortName,
partnerID: user.partnerId ? user.partnerId : '',
referrerUserId: referrerUserId ? referrerUserId : '',
password,
secret,
email: user.email,
partnerId: user.partnerId ? user.partnerId : '',
};
const response = await this.mutate(query, variables);
const response = await this.http.post(path, JSON.stringify(body), false);
if (!response.ok) {
throw new Error('can not register user');
}
return response.data.createUser.id;
return await response.json();
}
}

View File

@ -63,7 +63,7 @@ export class PaymentsHttpApi implements PaymentsApi {
const path = `${this.ROOT_PATH}/cards`;
const response = await this.client.post(path, token);
if (!response.ok) {
if (response.ok) {
return;
}

View File

@ -71,8 +71,8 @@ import VButton from '@/components/common/VButton.vue';
import ChangePasswordIcon from '@/../static/images/account/changePasswordPopup/changePassword.svg';
import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
import { AuthApi } from '@/api/auth';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import { AuthHttpApi } from '@/api/auth';
import { APP_STATE_ACTIONS, NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
import { validatePassword } from '@/utils/validation';
@Component({
@ -91,7 +91,7 @@ export default class ChangePasswordPopup extends Vue {
private newPasswordError: string = '';
private confirmationPasswordError: string = '';
private readonly auth: AuthApi = new AuthApi();
private readonly auth: AuthHttpApi = new AuthHttpApi();
public setOldPassword(value: string): void {
this.oldPassword = value;

View File

@ -51,7 +51,7 @@ import VButton from '@/components/common/VButton.vue';
import DeleteAccountIcon from '@/../static/images/account/deleteAccountPopup/deleteAccount.svg';
import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
import { AuthApi } from '@/api/auth';
import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router';
import { AuthToken } from '@/utils/authToken';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
@ -70,7 +70,7 @@ export default class DeleteAccountPopup extends Vue {
private password: string = '';
private isLoading: boolean = false;
private readonly auth: AuthApi = new AuthApi();
private readonly auth: AuthHttpApi = new AuthHttpApi();
public setPassword(value: string): void {
this.password = value;

View File

@ -11,7 +11,7 @@ import VButton from '@/components/common/VButton.vue';
import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
import RegistrationSuccessIcon from '@/../static/images/register/registerSuccess.svg';
import { AuthApi } from '@/api/auth';
import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router';
import { getUserId } from '@/utils/consoleLocalStorage';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
@ -28,7 +28,7 @@ export default class RegistrationSuccessPopup extends Vue {
private timeToEnableResendEmailButton: string = '00:30';
private intervalID: any = null;
private readonly auth: AuthApi = new AuthApi();
private readonly auth: AuthHttpApi = new AuthHttpApi();
public beforeDestroy(): void {
if (this.intervalID) {

View File

@ -5,13 +5,13 @@ import Vue from 'vue';
import Vuex from 'vuex';
import { ApiKeysApiGql } from '@/api/apiKeys';
import { AuthHttpApi } from '@/api/auth';
import { BucketsApiGql } from '@/api/buckets';
import { CreditsApiGql } from '@/api/credits';
import { PaymentsHttpApi } from '@/api/payments';
import { ProjectMembersApiGql } from '@/api/projectMembers';
import { ProjectsApiGql } from '@/api/projects';
import { ProjectUsageApiGql } from '@/api/usage';
import { UsersApiGql } from '@/api/users';
import { makeApiKeysModule } from '@/store/modules/apiKeys';
import { appStateModule } from '@/store/modules/appState';
import { makeBucketsModule } from '@/store/modules/buckets';
@ -33,7 +33,7 @@ export class StoreModule<S> {
}
// TODO: remove it after we will use modules as classes and use some DI framework
const usersApi = new UsersApiGql();
const authApi = new AuthHttpApi();
const apiKeysApi = new ApiKeysApiGql();
const creditsApi = new CreditsApiGql();
const bucketsApi = new BucketsApiGql();
@ -51,7 +51,7 @@ export const store = new Vuex.Store({
creditsModule: makeCreditsModule(creditsApi),
projectMembersModule: makeProjectMembersModule(projectMembersApi),
paymentsModule: makePaymentsModule(paymentsApi),
usersModule: makeUsersModule(usersApi),
usersModule: makeUsersModule(authApi),
projectsModule: makeProjectsModule(projectsApi),
usageModule: makeUsageModule(projectUsageApi),
bucketUsageModule: makeBucketsModule(bucketsApi),

View File

@ -30,13 +30,15 @@ export class User {
public shortName: string;
public email: string;
public partnerId: string;
public password: string;
public constructor(id: string = '', fullName: string = '', shortName: string = '', email: string = '', partnerId: string = '') {
public constructor(id: string = '', fullName: string = '', shortName: string = '', email: string = '', partnerId: string = '', password: string = '') {
this.id = id;
this.fullName = fullName;
this.shortName = shortName;
this.email = email;
this.partnerId = partnerId;
this.password = password;
}
public getFullName(): string {

View File

@ -54,6 +54,16 @@ export class HttpClient {
return this.sendJSON('PATCH', path, body, auth);
}
/**
* Performs PUT http request with JSON body.
* @param path
* @param body serialized JSON
* @param auth indicates if authentication is needed
*/
public async put(path: string, body: string | null, auth: boolean = true): Promise<Response> {
return this.sendJSON('PUT', path, body, auth);
}
/**
* Performs GET http request.
* @param path

View File

@ -11,7 +11,7 @@ import HeaderlessInput from '@/components/common/HeaderlessInput.vue';
import AuthIcon from '@/../static/images/AuthImage.svg';
import LogoIcon from '@/../static/images/Logo.svg';
import { AuthApi } from '@/api/auth';
import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router';
import { LOADING_CLASSES } from '@/utils/constants/classConstants';
import { validateEmail } from '@/utils/validation';
@ -28,7 +28,7 @@ export default class ForgotPassword extends Vue {
private email: string = '';
private emailError: string = '';
private readonly auth: AuthApi = new AuthApi();
private readonly auth: AuthHttpApi = new AuthHttpApi();
public setEmail(value: string): void {
this.email = value;

View File

@ -12,7 +12,7 @@ import AuthIcon from '@/../static/images/AuthImage.svg';
import LogoIcon from '@/../static/images/Logo.svg';
import LoadingLogoIcon from '@/../static/images/LogoWhite.svg';
import { AuthApi } from '@/api/auth';
import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router';
import { AuthToken } from '@/utils/authToken';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
@ -40,7 +40,7 @@ export default class Login extends Vue {
private emailError: string = '';
private passwordError: string = '';
private readonly auth: AuthApi = new AuthApi();
private readonly auth: AuthHttpApi = new AuthHttpApi();
public onLogoClick(): void {
location.reload();
@ -77,6 +77,7 @@ export default class Login extends Vue {
try {
this.authToken = await this.auth.token(this.email, this.password);
AuthToken.set(this.authToken);
} catch (error) {
await this.$notify.error(error.message);
this.isLoading = false;

View File

@ -14,7 +14,7 @@ import AuthIcon from '@/../static/images/AuthImage.svg';
import InfoIcon from '@/../static/images/info.svg';
import LogoIcon from '@/../static/images/Logo.svg';
import { AuthApi } from '@/api/auth';
import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router';
import { User } from '@/types/users';
import { setUserId } from '@/utils/consoleLocalStorage';
@ -53,7 +53,7 @@ export default class RegisterArea extends Vue {
private loadingClassName: string = LOADING_CLASSES.LOADING_OVERLAY;
private readonly auth: AuthApi = new AuthApi();
private readonly auth: AuthHttpApi = new AuthHttpApi();
async mounted(): Promise<void> {
if (this.$route.query.token) {
@ -116,6 +116,7 @@ export default class RegisterArea extends Vue {
this.user.shortName = value.trim();
}
public setPassword(value: string): void {
this.user.password = value.trim();
this.password = value;
this.passwordError = '';
}
@ -157,7 +158,7 @@ export default class RegisterArea extends Vue {
private async createUser(): Promise<void> {
try {
this.userId = await this.auth.create(this.user, this.password , this.secret, this.refUserId);
this.userId = await this.auth.register(this.user, this.secret, this.refUserId);
setUserId(this.userId);