web/satellite user api simplification (#2787)
This commit is contained in:
parent
2c769fe9d9
commit
012775f874
163
web/satellite/src/api/auth.ts
Normal file
163
web/satellite/src/api/auth.ts
Normal file
@ -0,0 +1,163 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { BaseGql } from '@/api/baseGql';
|
||||
import { User } from '@/types/users';
|
||||
|
||||
/**
|
||||
* AuthApiGql is a graphql implementation of Auth API.
|
||||
* Exposes all auth-related functionality
|
||||
*/
|
||||
export class AuthApi extends BaseGql {
|
||||
/**
|
||||
* Used to resend an registration confirmation email
|
||||
*
|
||||
* @param userId - id of newly created user
|
||||
* @throws Error
|
||||
*/
|
||||
public async resendEmail(userId: string): Promise<void> {
|
||||
const query =
|
||||
`query ($userId: String!){
|
||||
resendAccountActivationEmail(id: $userId)
|
||||
}`;
|
||||
|
||||
const variables = {
|
||||
userId,
|
||||
};
|
||||
|
||||
await this.query(query, variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to get authentication token
|
||||
*
|
||||
* @param email - email of the user
|
||||
* @param password - password of the user
|
||||
* @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 response = await this.query(query, variables);
|
||||
|
||||
return response.data.token.token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to restore password
|
||||
*
|
||||
* @param email - email of the user
|
||||
* @throws Error
|
||||
*/
|
||||
public async forgotPassword(email: string): Promise<void> {
|
||||
const query =
|
||||
`query($email: String!) {
|
||||
forgotPassword(email: $email)
|
||||
}`;
|
||||
|
||||
const variables = {
|
||||
email,
|
||||
};
|
||||
|
||||
await this.query(query, variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to change password
|
||||
*
|
||||
* @param password - old password of the user
|
||||
* @param newPassword - new password of the user
|
||||
* @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,
|
||||
};
|
||||
|
||||
await this.mutate(query, variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to delete account
|
||||
*
|
||||
* @param password - password of the user
|
||||
* @throws Error
|
||||
*/
|
||||
public async delete(password: string): Promise<void> {
|
||||
const query =
|
||||
`mutation ($password: String!){
|
||||
deleteAccount(password: $password) {
|
||||
email
|
||||
}
|
||||
}`;
|
||||
|
||||
const variables = {
|
||||
password,
|
||||
};
|
||||
|
||||
await this.mutate(query, variables);
|
||||
}
|
||||
|
||||
// TODO: remove secret after Vanguard release
|
||||
/**
|
||||
* Used to create account
|
||||
*
|
||||
* @param user - stores user information
|
||||
* @param secret - registration token used in Vanguard release
|
||||
* @param refUserId - 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,
|
||||
fullName: user.fullName,
|
||||
shortName: user.shortName,
|
||||
partnerID: user.partnerId ? user.partnerId : '',
|
||||
referrerUserId: referrerUserId ? referrerUserId : '',
|
||||
password,
|
||||
secret,
|
||||
};
|
||||
|
||||
const response = await this.mutate(query, variables);
|
||||
|
||||
return response.data.createUser.id;
|
||||
}
|
||||
}
|
62
web/satellite/src/api/baseGql.ts
Normal file
62
web/satellite/src/api/baseGql.ts
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import gql from 'graphql-tag';
|
||||
import apolloManager from '@/utils/apolloManager';
|
||||
|
||||
/**
|
||||
* BaseGql is a graphql utility which allows to perform queries and mutations
|
||||
*/
|
||||
export class BaseGql {
|
||||
/**
|
||||
* performs qraphql query
|
||||
*
|
||||
* @param query - qraphql query
|
||||
* @param variables - variables to bind in query. null by default.
|
||||
* @throws Error
|
||||
*/
|
||||
protected async query(query: string, variables: any = null): Promise<any> {
|
||||
let response: any = await apolloManager.query(
|
||||
{
|
||||
query: gql(query),
|
||||
variables,
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all',
|
||||
}
|
||||
);
|
||||
|
||||
if (response.errors) {
|
||||
throw new Error(this.combineErrors(response.errors));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* performs qraphql mutation
|
||||
*
|
||||
* @param query - qraphql query
|
||||
* @param variables - variables to bind in query. null by default.
|
||||
* @throws Error
|
||||
*/
|
||||
protected async mutate(query: string, variables: any = null): Promise<any> {
|
||||
let response: any = await apolloManager.mutate(
|
||||
{
|
||||
mutation: gql(query),
|
||||
variables,
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all',
|
||||
}
|
||||
);
|
||||
|
||||
if (response.errors) {
|
||||
throw new Error(this.combineErrors(response.errors));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private combineErrors(gqlError: any): string {
|
||||
return gqlError.map(err => err.message).join('\n');
|
||||
}
|
||||
}
|
@ -1,276 +1,68 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import apolloManager from '@/utils/apolloManager';
|
||||
import gql from 'graphql-tag';
|
||||
import { UpdatedUser, User } from '@/types/users';
|
||||
import { RequestResponse } from '@/types/response';
|
||||
import { BaseGql } from '@/api/baseGql';
|
||||
import { UpdatedUser, User, UsersApi } from '@/types/users';
|
||||
|
||||
// Performs update user info graphQL mutation request.
|
||||
// Returns User object if succeed, null otherwise
|
||||
export async function updateAccountRequest(user: UpdatedUser): Promise<RequestResponse<User>> {
|
||||
let result: RequestResponse<User> = new RequestResponse<User>();
|
||||
/**
|
||||
* UsersApiGql is a graphql implementation of Users API.
|
||||
* Exposes all user-related functionality
|
||||
*/
|
||||
export class UsersApiGql extends BaseGql implements UsersApi {
|
||||
|
||||
let response: any = await apolloManager.mutate(
|
||||
{
|
||||
mutation: gql(`
|
||||
mutation {
|
||||
updateAccount (
|
||||
input: {
|
||||
fullName: $fullName,
|
||||
shortName: $shortName
|
||||
}
|
||||
) {
|
||||
email,
|
||||
fullName,
|
||||
shortName
|
||||
/**
|
||||
* Updates users full name and short name
|
||||
*
|
||||
* @param user - contains information that should be updated
|
||||
* @throws Error
|
||||
*/
|
||||
public async update(user: UpdatedUser): Promise<void> {
|
||||
const query: string =
|
||||
`mutation ($fullName: String!, $shortName: String!) {
|
||||
updateAccount (
|
||||
input: {
|
||||
fullName: $fullName,
|
||||
shortName: $shortName
|
||||
}
|
||||
}`,
|
||||
),
|
||||
variables: {
|
||||
fullName: user.fullName,
|
||||
shortName: user.fullName,
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all',
|
||||
}
|
||||
);
|
||||
) {
|
||||
email,
|
||||
fullName,
|
||||
shortName
|
||||
}
|
||||
}`;
|
||||
|
||||
if (response.errors) {
|
||||
result.errorMessage = response.errors[0].message;
|
||||
} else {
|
||||
result.isSuccess = true;
|
||||
result.data = response.data.updateAccount;
|
||||
const variables: any = {
|
||||
fullName: user.fullName,
|
||||
shortName: user.shortName,
|
||||
};
|
||||
|
||||
await this.mutate(query, variables);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Fetch user
|
||||
*
|
||||
* @returns User
|
||||
* @throws Error
|
||||
*/
|
||||
public async get(): Promise<User> {
|
||||
const query =
|
||||
` query {
|
||||
user {
|
||||
id,
|
||||
fullName,
|
||||
shortName,
|
||||
email,
|
||||
partnerId,
|
||||
}
|
||||
}`;
|
||||
|
||||
// Performs change password graphQL mutation
|
||||
// Returns base user fields
|
||||
export async function changePasswordRequest(password: string, newPassword: string): Promise<RequestResponse<null>> {
|
||||
let result: RequestResponse<null> = new RequestResponse<null>();
|
||||
const response = await this.query(query);
|
||||
|
||||
let response: any = await apolloManager.mutate(
|
||||
{
|
||||
mutation: gql(`
|
||||
mutation($password: String!, $newPassword: String!) {
|
||||
changePassword (
|
||||
password: $password,
|
||||
newPassword: $newPassword
|
||||
) {
|
||||
email
|
||||
}
|
||||
}`
|
||||
),
|
||||
variables: {
|
||||
password: password,
|
||||
newPassword: newPassword
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all',
|
||||
}
|
||||
);
|
||||
|
||||
if (response.errors) {
|
||||
result.errorMessage = response.errors[0].message;
|
||||
} else {
|
||||
result.isSuccess = true;
|
||||
return this.fromJson(response.data.user);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function forgotPasswordRequest(email: string): Promise<RequestResponse<null>> {
|
||||
let result: RequestResponse<null> = new RequestResponse<null>();
|
||||
|
||||
let response: any = await apolloManager.query(
|
||||
{
|
||||
query: gql(`
|
||||
query($email: String!) {
|
||||
forgotPassword(email: $email)
|
||||
}`),
|
||||
variables: {
|
||||
email: email
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.errors) {
|
||||
result.errorMessage = response.errors[0].message;
|
||||
} else {
|
||||
result.isSuccess = true;
|
||||
private fromJson(user): User {
|
||||
return new User(user.id, user.fullName, user.shortName, user.email, user.partnerId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Performs Create user graqhQL request.
|
||||
export async function createUserRequest(user: User, password: string, secret: string, refUserId?: string): Promise<RequestResponse<string>> {
|
||||
let result: RequestResponse<string> = new RequestResponse<string>();
|
||||
|
||||
let response = await apolloManager.mutate(
|
||||
{
|
||||
mutation: gql(`
|
||||
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}
|
||||
}`
|
||||
),
|
||||
variables: {
|
||||
email: user.email,
|
||||
password: password,
|
||||
fullName: user.fullName,
|
||||
shortName: user.shortName,
|
||||
partnerID: user.partnerId ? user.partnerId : '',
|
||||
referrerUserID: refUserId ? refUserId : '',
|
||||
secret: secret
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all',
|
||||
}
|
||||
);
|
||||
|
||||
if (response.errors) {
|
||||
result.errorMessage = response.errors[0].message;
|
||||
} else {
|
||||
result.isSuccess = true;
|
||||
if (response.data) {
|
||||
result.data = response.data.createUser.id;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Performs graqhQL request.
|
||||
// Returns Token.
|
||||
export async function getTokenRequest(email: string, password: string): Promise<RequestResponse<string>> {
|
||||
let result: RequestResponse<string> = new RequestResponse<string>();
|
||||
|
||||
let response: any = await apolloManager.query(
|
||||
{
|
||||
query: gql(`
|
||||
query ($email: String!, $password: String!) {
|
||||
token(email: $email, password: $password) {
|
||||
token
|
||||
}
|
||||
}`
|
||||
),
|
||||
variables: {
|
||||
email: email,
|
||||
password: password
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all',
|
||||
}
|
||||
);
|
||||
|
||||
if (response.errors) {
|
||||
result.errorMessage = response.errors[0].message;
|
||||
} else {
|
||||
result.isSuccess = true;
|
||||
result.data = response.data.token.token;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Performs graqhQL request.
|
||||
// Returns User object.
|
||||
export async function getUserRequest(): Promise<RequestResponse<User>> {
|
||||
let result: RequestResponse<User> = new RequestResponse<User>();
|
||||
|
||||
let response: any = await apolloManager.query(
|
||||
{
|
||||
query: gql(`
|
||||
query {
|
||||
user {
|
||||
fullName,
|
||||
shortName,
|
||||
email,
|
||||
}
|
||||
}`
|
||||
),
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all',
|
||||
}
|
||||
);
|
||||
|
||||
if (response.errors) {
|
||||
result.errorMessage = response.errors[0].message;
|
||||
} else {
|
||||
result.isSuccess = true;
|
||||
result.data = response.data.user;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Performs graqhQL request.
|
||||
export async function deleteAccountRequest(password: string): Promise<RequestResponse<null>> {
|
||||
let result: RequestResponse<null> = new RequestResponse<null>();
|
||||
|
||||
let response = await apolloManager.mutate(
|
||||
{
|
||||
mutation: gql(`
|
||||
mutation ($password: String!){
|
||||
deleteAccount(password: $password) {
|
||||
email
|
||||
}
|
||||
}`
|
||||
),
|
||||
variables: {
|
||||
password: password
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all',
|
||||
}
|
||||
);
|
||||
|
||||
if (response.errors) {
|
||||
result.errorMessage = response.errors[0].message;
|
||||
} else {
|
||||
result.isSuccess = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function resendEmailRequest(userID: string): Promise<RequestResponse<null>> {
|
||||
let result: RequestResponse<null> = new RequestResponse<null>();
|
||||
|
||||
let response = await apolloManager.query(
|
||||
{
|
||||
query: gql(`
|
||||
query ($userID: String!){
|
||||
resendAccountActivationEmail(id: $userID)
|
||||
}`
|
||||
),
|
||||
variables: {
|
||||
userID: userID
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all',
|
||||
}
|
||||
);
|
||||
|
||||
if (response.errors) {
|
||||
result.errorMessage = response.errors[0].message;
|
||||
} else {
|
||||
result.isSuccess = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -63,9 +63,9 @@
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import HeaderlessInput from '@/components/common/HeaderlessInput.vue';
|
||||
import Button from '@/components/common/Button.vue';
|
||||
import { USER_ACTIONS, NOTIFICATION_ACTIONS, APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { NOTIFICATION_ACTIONS, APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { validatePassword } from '@/utils/validation';
|
||||
import { RequestResponse } from '@/types/response';
|
||||
import { AuthApi } from '@/api/auth';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@ -81,6 +81,8 @@
|
||||
private newPasswordError: string = '';
|
||||
private confirmationPasswordError: string = '';
|
||||
|
||||
private readonly auth: AuthApi = new AuthApi();
|
||||
|
||||
public setOldPassword(value: string): void {
|
||||
this.oldPassword = value;
|
||||
this.oldPasswordError = '';
|
||||
@ -122,63 +124,21 @@
|
||||
return;
|
||||
}
|
||||
|
||||
let response: RequestResponse<object> = await this.$store.dispatch(USER_ACTIONS.CHANGE_PASSWORD,
|
||||
{
|
||||
oldPassword: this.oldPassword,
|
||||
newPassword: this.newPassword
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, response.errorMessage);
|
||||
try {
|
||||
await this.auth.changePassword(this.oldPassword, this.newPassword);
|
||||
} catch (error) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, error.message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Password successfully changed!');
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_CHANGE_PASSWORD_POPUP);
|
||||
|
||||
this.oldPassword = '';
|
||||
this.newPassword = '';
|
||||
this.confirmationPassword = '';
|
||||
|
||||
this.oldPasswordError = '';
|
||||
this.newPasswordError = '';
|
||||
this.confirmationPasswordError = '';
|
||||
|
||||
let oldPasswordInput: any = this.$refs['oldPasswordInput'];
|
||||
oldPasswordInput.setValue('');
|
||||
|
||||
let newPasswordInput: any = this.$refs['newPasswordInput'];
|
||||
newPasswordInput.setValue('');
|
||||
|
||||
let confirmPasswordInput: any = this.$refs['confirmPasswordInput'];
|
||||
confirmPasswordInput.setValue('');
|
||||
}
|
||||
|
||||
public onCloseClick(): void {
|
||||
this.cancel();
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_CHANGE_PASSWORD_POPUP);
|
||||
}
|
||||
|
||||
private cancel(): void {
|
||||
this.oldPassword = '';
|
||||
this.newPassword = '';
|
||||
this.confirmationPassword = '';
|
||||
|
||||
this.oldPasswordError = '';
|
||||
this.newPasswordError = '';
|
||||
this.confirmationPasswordError = '';
|
||||
|
||||
let oldPasswordInput: any = this.$refs['oldPasswordInput'];
|
||||
oldPasswordInput.setValue('');
|
||||
|
||||
let newPasswordInput: any = this.$refs['newPasswordInput'];
|
||||
newPasswordInput.setValue('');
|
||||
|
||||
let confirmPasswordInput: any = this.$refs['confirmPasswordInput'];
|
||||
confirmPasswordInput.setValue('');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -64,11 +64,12 @@
|
||||
|
||||
<script lang='ts'>
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import HeaderedInput from '@/components/common/HeaderedInput.vue';
|
||||
import { AuthApi } from '@/api/auth';
|
||||
import Button from '@/components/common/Button.vue';
|
||||
import HeaderedInput from '@/components/common/HeaderedInput.vue';
|
||||
import { APP_STATE_ACTIONS, NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { AuthToken } from '@/utils/authToken';
|
||||
import { APP_STATE_ACTIONS, USER_ACTIONS, NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { RequestResponse } from '@/types/response';
|
||||
import ROUTES from '@/utils/constants/routerConstants';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@ -81,6 +82,8 @@
|
||||
private password: string = '';
|
||||
private isLoading: boolean = false;
|
||||
|
||||
private readonly auth: AuthApi = new AuthApi();
|
||||
|
||||
public setPassword(value: string): void {
|
||||
this.password = value;
|
||||
}
|
||||
@ -92,20 +95,18 @@
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
let response: RequestResponse<object> = await this.$store.dispatch(USER_ACTIONS.DELETE, this.password);
|
||||
try {
|
||||
await this.auth.delete(this.password);
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Account was successfully deleted');
|
||||
|
||||
AuthToken.remove();
|
||||
|
||||
if (!response.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, response.errorMessage);
|
||||
this.isLoading = false;
|
||||
|
||||
return;
|
||||
this.$router.push(ROUTES.LOGIN.path);
|
||||
} catch (error) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, error.message);
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Account was successfully deleted');
|
||||
AuthToken.remove();
|
||||
|
||||
this.isLoading = false;
|
||||
this.$router.push('/login');
|
||||
}
|
||||
|
||||
public onCloseClick(): void {
|
||||
|
@ -18,7 +18,7 @@
|
||||
width="100%"
|
||||
ref="fullNameInput"
|
||||
:error="fullNameError"
|
||||
:initValue="originalFullName"
|
||||
:initValue="userInfo.fullName"
|
||||
@setData="setFullName" />
|
||||
<HeaderedInput
|
||||
class="full-input"
|
||||
@ -26,7 +26,7 @@
|
||||
placeholder="Enter Nickname"
|
||||
width="100%"
|
||||
ref="shortNameInput"
|
||||
:initValue="originalShortName"
|
||||
:initValue="userInfo.shortName"
|
||||
@setData="setShortName"/>
|
||||
<div class="edit-profile-popup__form-container__button-container">
|
||||
<Button label="Cancel" width="205px" height="48px" :onPress="onCloseClick" isWhite="true" />
|
||||
@ -47,6 +47,7 @@
|
||||
import HeaderedInput from '@/components/common/HeaderedInput.vue';
|
||||
import Button from '@/components/common/Button.vue';
|
||||
import { USER_ACTIONS, NOTIFICATION_ACTIONS, APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { UpdatedUser } from '@/types/users';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@ -55,61 +56,41 @@
|
||||
}
|
||||
})
|
||||
export default class EditProfilePopup extends Vue {
|
||||
private originalFullName: string = this.$store.getters.user.fullName;
|
||||
private originalShortName: string = this.$store.getters.user.shortName;
|
||||
private fullName: string = this.$store.getters.user.fullName;
|
||||
private shortName: string = this.$store.getters.user.shortName;
|
||||
private fullNameError: string = '';
|
||||
|
||||
private readonly userInfo: UpdatedUser =
|
||||
new UpdatedUser(this.$store.getters.user.fullName, this.$store.getters.user.shortName);
|
||||
|
||||
public setFullName(value: string): void {
|
||||
this.fullName = value.trim();
|
||||
this.userInfo.setFullName(value);
|
||||
this.fullNameError = '';
|
||||
}
|
||||
|
||||
public setShortName(value: string): void {
|
||||
this.shortName = value.trim();
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
this.fullName = this.originalFullName;
|
||||
this.fullNameError = '';
|
||||
this.shortName = this.originalShortName;
|
||||
|
||||
let fullNameInput: any = this.$refs['fullNameInput'];
|
||||
fullNameInput.setValue(this.originalFullName);
|
||||
|
||||
let shortNameInput: any = this.$refs['shortNameInput'];
|
||||
shortNameInput.setValue(this.originalShortName);
|
||||
this.userInfo.setShortName(value);
|
||||
}
|
||||
|
||||
public async onUpdateClick(): Promise<void> {
|
||||
if (!this.fullName) {
|
||||
if (!this.userInfo.isValid()) {
|
||||
this.fullNameError = 'Full name expected';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let user = {
|
||||
fullName: this.fullName,
|
||||
shortName: this.shortName,
|
||||
};
|
||||
|
||||
let response = await this.$store.dispatch(USER_ACTIONS.UPDATE, user);
|
||||
if (!response.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, response.errorMessage);
|
||||
try {
|
||||
await this.$store.dispatch(USER_ACTIONS.UPDATE, this.userInfo);
|
||||
} catch (error) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, error.message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Account info successfully updated!');
|
||||
|
||||
this.originalFullName = this.$store.getters.user.fullName;
|
||||
this.originalShortName = this.$store.getters.user.shortName;
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_EDIT_PROFILE_POPUP);
|
||||
}
|
||||
|
||||
public onCloseClick(): void {
|
||||
this.cancel();
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_EDIT_PROFILE_POPUP);
|
||||
}
|
||||
|
||||
|
@ -6,10 +6,10 @@
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import Button from '@/components/common/Button.vue';
|
||||
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { APP_STATE_ACTIONS, NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import ROUTES from '@/utils/constants/routerConstants';
|
||||
import { resendEmailRequest } from '../../api/users';
|
||||
import { getUserID } from '@/utils/consoleLocalStorage';
|
||||
import { AuthApi } from '@/api/auth';
|
||||
import { getUserId } from '@/utils/consoleLocalStorage';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@ -21,6 +21,8 @@
|
||||
private timeToEnableResendEmailButton: string = '00:30';
|
||||
private intervalID: any = null;
|
||||
|
||||
private readonly auth: AuthApi = new AuthApi();
|
||||
|
||||
public beforeDestroy(): void {
|
||||
if (this.intervalID) {
|
||||
clearInterval(this.intervalID);
|
||||
@ -30,15 +32,18 @@
|
||||
public async onResendEmailButtonClick(): Promise<void> {
|
||||
this.isResendEmailButtonDisabled = true;
|
||||
|
||||
let userID = getUserID();
|
||||
if (!userID) {
|
||||
const userId = getUserId();
|
||||
if (!userId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let response = await resendEmailRequest(userID);
|
||||
if (response.isSuccess) {
|
||||
this.startResendEmailCountdown();
|
||||
try {
|
||||
await this.auth.resendEmail(userId);
|
||||
} catch (error) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'could not send email ');
|
||||
}
|
||||
|
||||
this.startResendEmailCountdown();
|
||||
}
|
||||
|
||||
public onCloseClick(): void {
|
||||
@ -52,19 +57,18 @@
|
||||
|
||||
private startResendEmailCountdown(): void {
|
||||
let countdown = 30;
|
||||
let self = this;
|
||||
|
||||
this.intervalID = setInterval(function () {
|
||||
this.intervalID = setInterval(() => {
|
||||
countdown--;
|
||||
|
||||
let secondsLeft = countdown > 9 ? countdown : `0${countdown}`;
|
||||
self.timeToEnableResendEmailButton = `00:${secondsLeft}`;
|
||||
this.timeToEnableResendEmailButton = `00:${secondsLeft}`;
|
||||
|
||||
if (countdown <= 0) {
|
||||
clearInterval(self.intervalID);
|
||||
self.isResendEmailButtonDisabled = false;
|
||||
clearInterval(this.intervalID);
|
||||
this.isResendEmailButtonDisabled = false;
|
||||
}
|
||||
}.bind(this), 1000);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -4,8 +4,7 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
|
||||
import { usersModule } from '@/store/modules/users';
|
||||
import { makeUsersModule } from '@/store/modules/users';
|
||||
import { projectsModule } from '@/store/modules/projects';
|
||||
import { projectMembersModule } from '@/store/modules/projectMembers';
|
||||
import { notificationsModule } from '@/store/modules/notifications';
|
||||
@ -13,13 +12,23 @@ import { appStateModule } from '@/store/modules/appState';
|
||||
import { apiKeysModule } from '@/store/modules/apiKeys';
|
||||
import { bucketUsageModule, usageModule, creditUsageModule } from '@/store/modules/usage';
|
||||
import { projectPaymentsMethodsModule } from '@/store/modules/paymentMethods';
|
||||
import { UsersApiGql } from '@/api/users';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export class StoreModule<S> {
|
||||
public state: S;
|
||||
public mutations: any;
|
||||
public actions: any;
|
||||
public getters: any;
|
||||
}
|
||||
|
||||
const usersApi = new UsersApiGql();
|
||||
|
||||
// Satellite store (vuex)
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
usersModule,
|
||||
usersModule: makeUsersModule(usersApi),
|
||||
projectsModule,
|
||||
projectMembersModule,
|
||||
notificationsModule,
|
||||
|
@ -2,82 +2,68 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { USER_MUTATIONS } from '../mutationConstants';
|
||||
import {
|
||||
deleteAccountRequest,
|
||||
updateAccountRequest,
|
||||
changePasswordRequest,
|
||||
getUserRequest,
|
||||
} from '@/api/users';
|
||||
import { UpdatedUser, UpdatePasswordModel, User } from '@/types/users';
|
||||
import { RequestResponse } from '@/types/response';
|
||||
import { UpdatedUser, User, UsersApi } from '@/types/users';
|
||||
import { StoreModule } from '@/store';
|
||||
|
||||
export const usersModule = {
|
||||
state: {
|
||||
user: {
|
||||
fullName: '',
|
||||
shortName: '',
|
||||
email: ''
|
||||
}
|
||||
},
|
||||
const {
|
||||
SET_USER,
|
||||
UPDATE_USER,
|
||||
CLEAR,
|
||||
} = USER_MUTATIONS;
|
||||
|
||||
mutations: {
|
||||
[USER_MUTATIONS.SET_USER_INFO](state: any, user: User): void {
|
||||
state.user = user;
|
||||
/**
|
||||
* creates users module with all dependencies
|
||||
*
|
||||
* @param api - users api
|
||||
*/
|
||||
export function makeUsersModule(api: UsersApi): StoreModule<User> {
|
||||
return {
|
||||
state: new User(),
|
||||
|
||||
mutations: {
|
||||
setUser(state: User, user: User): void {
|
||||
state.id = user.id;
|
||||
state.email = user.email;
|
||||
state.shortName = user.shortName;
|
||||
state.fullName = user.fullName;
|
||||
state.partnerId = user.partnerId;
|
||||
},
|
||||
|
||||
clearUser(state: User): void {
|
||||
state.id = '';
|
||||
state.email = '';
|
||||
state.shortName = '';
|
||||
state.fullName = '';
|
||||
state.partnerId = '';
|
||||
},
|
||||
|
||||
updateUser(state: User, user: UpdatedUser): void {
|
||||
state.fullName = user.fullName;
|
||||
state.shortName = user.shortName;
|
||||
},
|
||||
},
|
||||
|
||||
[USER_MUTATIONS.REVERT_TO_DEFAULT_USER_INFO](state: any): void {
|
||||
state.user.fullName = '';
|
||||
state.user.shortName = '';
|
||||
state.user.email = '';
|
||||
actions: {
|
||||
updateUser: async function ({commit}: any, userInfo: UpdatedUser): Promise<void> {
|
||||
await api.update(userInfo);
|
||||
|
||||
commit(UPDATE_USER, userInfo);
|
||||
},
|
||||
getUser: async function ({commit}: any): Promise<User> {
|
||||
let user = await api.get();
|
||||
|
||||
commit(SET_USER, user);
|
||||
|
||||
return user;
|
||||
},
|
||||
clearUser: function({commit}: any) {
|
||||
commit(CLEAR);
|
||||
},
|
||||
},
|
||||
|
||||
[USER_MUTATIONS.UPDATE_USER_INFO](state: any, user: User): void {
|
||||
state.user = user;
|
||||
getters: {
|
||||
user: (state: User): User => state,
|
||||
userName: (state: User): string => state.getFullName(),
|
||||
},
|
||||
|
||||
[USER_MUTATIONS.CLEAR](state: any): void {
|
||||
state.user = {
|
||||
fullName: '',
|
||||
shortName: '',
|
||||
email: ''
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
updateAccount: async function ({commit}: any, userInfo: UpdatedUser): Promise<RequestResponse<User>> {
|
||||
let response = await updateAccountRequest(userInfo);
|
||||
|
||||
if (response.isSuccess) {
|
||||
commit(USER_MUTATIONS.UPDATE_USER_INFO, response.data);
|
||||
}
|
||||
|
||||
return response;
|
||||
},
|
||||
changePassword: async function ({state}: any, updateModel: UpdatePasswordModel): Promise<RequestResponse<null>> {
|
||||
return await changePasswordRequest(updateModel.oldPassword, updateModel.newPassword);
|
||||
},
|
||||
deleteAccount: async function ({commit, state}: any, password: string): Promise<RequestResponse<null>> {
|
||||
return await deleteAccountRequest(password);
|
||||
},
|
||||
getUser: async function ({commit}: any): Promise<RequestResponse<User>> {
|
||||
let response = await getUserRequest();
|
||||
|
||||
if (response.isSuccess) {
|
||||
commit(USER_MUTATIONS.SET_USER_INFO, response.data);
|
||||
}
|
||||
|
||||
return response;
|
||||
},
|
||||
clearUser: function({commit}: any) {
|
||||
commit(USER_MUTATIONS.CLEAR);
|
||||
},
|
||||
},
|
||||
|
||||
getters: {
|
||||
user: (state: any) => {
|
||||
return state.user;
|
||||
},
|
||||
userName: (state: any) => state.user.shortName == '' ? state.user.fullName : state.user.shortName
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -2,10 +2,9 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
export const USER_MUTATIONS = {
|
||||
SET_USER_INFO: 'SET_USER_INFO',
|
||||
REVERT_TO_DEFAULT_USER_INFO: 'REVERT_TO_DEFAULT_USER_INFO',
|
||||
UPDATE_USER_INFO: 'UPDATE_USER_INFO',
|
||||
CLEAR: 'CLEAR_USER',
|
||||
SET_USER: 'setUser',
|
||||
UPDATE_USER: 'updateUser',
|
||||
CLEAR: 'clearUser',
|
||||
};
|
||||
|
||||
export const PROJECTS_MUTATIONS = {
|
||||
|
@ -1,19 +1,42 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
/**
|
||||
* Exposes all user-related functionality
|
||||
*/
|
||||
export interface UsersApi {
|
||||
/**
|
||||
* Updates users full name and short name
|
||||
*
|
||||
* @param user - contains information that should be updated
|
||||
* @throws Error
|
||||
*/
|
||||
update(user: UpdatedUser): Promise<void>;
|
||||
/**
|
||||
* Fetch user
|
||||
*
|
||||
* @returns User
|
||||
* @throws Error
|
||||
*/
|
||||
get(): Promise<User>;
|
||||
}
|
||||
|
||||
/**
|
||||
* User class holds info for User entity.
|
||||
*/
|
||||
export class User {
|
||||
public id: string;
|
||||
public fullName: string;
|
||||
public shortName: string;
|
||||
public email: string;
|
||||
public partnerId?: string;
|
||||
public partnerId: string;
|
||||
|
||||
public constructor(fullName: string, shortName: string, email: string, partnerId?: string) {
|
||||
this.id = '';
|
||||
public constructor(id: string = '', fullName: string = '', shortName: string = '', email: string = '', partnerId: string = '') {
|
||||
this.id = id;
|
||||
this.fullName = fullName;
|
||||
this.shortName = shortName;
|
||||
this.email = email;
|
||||
this.partnerId = partnerId || '';
|
||||
this.partnerId = partnerId;
|
||||
}
|
||||
|
||||
public getFullName(): string {
|
||||
@ -21,13 +44,27 @@ export class User {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User class holds info for updating User.
|
||||
*/
|
||||
export class UpdatedUser {
|
||||
public fullName: string;
|
||||
public shortName: string;
|
||||
}
|
||||
|
||||
// Used in users module to pass parameters to action
|
||||
export class UpdatePasswordModel {
|
||||
public oldPassword: string;
|
||||
public newPassword: string;
|
||||
public constructor(fullName: string, shortName: string) {
|
||||
this.fullName = fullName;
|
||||
this.shortName = shortName;
|
||||
}
|
||||
|
||||
public setFullName(value: string) {
|
||||
this.fullName = value.trim();
|
||||
}
|
||||
|
||||
public setShortName(value: string) {
|
||||
this.shortName = value.trim();
|
||||
}
|
||||
|
||||
public isValid(): boolean {
|
||||
return !!this.fullName;
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
const localStorageConstants = {
|
||||
USER_ID: 'userID',
|
||||
USER_EMAIL: 'userEmail'
|
||||
};
|
||||
const USER_ID: string = 'userID';
|
||||
|
||||
export function setUserId(userID: string) {
|
||||
localStorage.setItem(localStorageConstants.USER_ID, userID);
|
||||
export function setUserId(userId: string) {
|
||||
localStorage.setItem(USER_ID, userId);
|
||||
}
|
||||
|
||||
export function getUserID() {
|
||||
return localStorage.getItem(localStorageConstants.USER_ID);
|
||||
export function getUserId() {
|
||||
return localStorage.getItem(USER_ID);
|
||||
}
|
||||
|
@ -54,12 +54,9 @@ export const PROJETS_ACTIONS = {
|
||||
};
|
||||
|
||||
export const USER_ACTIONS = {
|
||||
UPDATE: 'updateAccount',
|
||||
CHANGE_PASSWORD: 'changePassword',
|
||||
DELETE: 'deleteAccount',
|
||||
UPDATE: 'updateUser',
|
||||
GET: 'getUser',
|
||||
CLEAR: 'clearUser',
|
||||
ACTIVATE: 'activateAccount',
|
||||
};
|
||||
|
||||
export const API_KEYS_ACTIONS = {
|
||||
|
@ -44,10 +44,13 @@
|
||||
@Component({
|
||||
mounted: async function() {
|
||||
setTimeout(async () => {
|
||||
let response: RequestResponse<User> = await this.$store.dispatch(USER_ACTIONS.GET);
|
||||
if (!response.isSuccess) {
|
||||
let user: User;
|
||||
|
||||
try {
|
||||
user = await this.$store.dispatch(USER_ACTIONS.GET);
|
||||
} catch (error) {
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.ERROR);
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, response.errorMessage);
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, error.message);
|
||||
this.$router.push(ROUTES.LOGIN);
|
||||
AuthToken.remove();
|
||||
|
||||
|
@ -7,11 +7,11 @@
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import HeaderlessInput from '@/components/common/HeaderlessInput.vue';
|
||||
import { LOADING_CLASSES } from '@/utils/constants/classConstants';
|
||||
import { forgotPasswordRequest } from '@/api/users';
|
||||
import { NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import ROUTES from '@/utils/constants/routerConstants';
|
||||
import { validateEmail } from '@/utils/validation';
|
||||
import EVENTS from '@/utils/constants/analyticsEventNames';
|
||||
import { AuthApi } from '@/api/auth';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@ -23,6 +23,8 @@
|
||||
private email: string = '';
|
||||
private emailError: string = '';
|
||||
|
||||
private readonly auth: AuthApi = new AuthApi();
|
||||
|
||||
public setEmail(value: string): void {
|
||||
this.email = value;
|
||||
this.emailError = '';
|
||||
@ -35,14 +37,12 @@
|
||||
return;
|
||||
}
|
||||
|
||||
let passwordRecoveryResponse = await forgotPasswordRequest(this.email);
|
||||
if (!passwordRecoveryResponse.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, passwordRecoveryResponse.errorMessage);
|
||||
|
||||
return;
|
||||
try {
|
||||
await this.auth.forgotPassword(this.email);
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Please look for instructions at your email');
|
||||
} catch (error) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, error.message);
|
||||
}
|
||||
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Please look for instructions at your email');
|
||||
}
|
||||
|
||||
public onBackToLoginClick(): void {
|
||||
|
@ -10,7 +10,7 @@
|
||||
import { AuthToken } from '@/utils/authToken';
|
||||
import ROUTES from '@/utils/constants/routerConstants';
|
||||
import { APP_STATE_ACTIONS, NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { getTokenRequest } from '@/api/users';
|
||||
import { AuthApi } from '@/api/auth';
|
||||
import { LOADING_CLASSES } from '@/utils/constants/classConstants';
|
||||
import { AppState } from '@/utils/constants/appStateEnum';
|
||||
import { validateEmail, validatePassword } from '@/utils/validation';
|
||||
@ -23,14 +23,18 @@
|
||||
}
|
||||
})
|
||||
export default class Login extends Vue {
|
||||
public forgotPasswordRouterPath: string = ROUTES.FORGOT_PASSWORD.path;
|
||||
private email: string = '';
|
||||
private password: string = '';
|
||||
private authToken: string = '';
|
||||
|
||||
public forgotPasswordRouterPath: string = ROUTES.FORGOT_PASSWORD.path;
|
||||
private loadingClassName: string = LOADING_CLASSES.LOADING_OVERLAY;
|
||||
private loadingLogoClassName: string = LOADING_CLASSES.LOADING_LOGO;
|
||||
private emailError: string = '';
|
||||
private passwordError: string = '';
|
||||
|
||||
private readonly auth: AuthApi = new AuthApi();
|
||||
|
||||
public onLogoClick(): void {
|
||||
location.reload();
|
||||
}
|
||||
@ -57,9 +61,10 @@
|
||||
return;
|
||||
}
|
||||
|
||||
let loginResponse = await getTokenRequest(this.email, this.password);
|
||||
if (!loginResponse.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, loginResponse.errorMessage);
|
||||
try {
|
||||
this.authToken = await this.auth.token(this.email, this.password);
|
||||
} catch (error) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, error.message);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -67,7 +72,7 @@
|
||||
this.activateLoadingOverlay();
|
||||
|
||||
setTimeout(() => {
|
||||
AuthToken.set(loginResponse.data);
|
||||
AuthToken.set(this.authToken);
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.LOADING);
|
||||
this.$router.push(ROUTES.PROJECT_OVERVIEW.path + '/' + ROUTES.PROJECT_DETAILS.path);
|
||||
}, 2000);
|
||||
|
@ -12,7 +12,7 @@
|
||||
import EVENTS from '../../utils/constants/analyticsEventNames';
|
||||
import { LOADING_CLASSES } from '../../utils/constants/classConstants';
|
||||
import { APP_STATE_ACTIONS, NOTIFICATION_ACTIONS } from '../../utils/constants/actionNames';
|
||||
import { createUserRequest } from '../../api/users';
|
||||
import { AuthApi } from '../../api/auth';
|
||||
import { setUserId } from '@/utils/consoleLocalStorage';
|
||||
import { User } from '../../types/users';
|
||||
import InfoComponent from '../../components/common/InfoComponent.vue';
|
||||
@ -25,22 +25,28 @@
|
||||
},
|
||||
})
|
||||
export default class Register extends Vue {
|
||||
private fullName: string = '';
|
||||
private fullNameError: string = '';
|
||||
private shortName: string = '';
|
||||
private email: string = '';
|
||||
private emailError: string = '';
|
||||
private password: string = '';
|
||||
private passwordError: string = '';
|
||||
private repeatedPassword: string = '';
|
||||
private repeatedPasswordError: string = '';
|
||||
private isTermsAccepted: boolean = false;
|
||||
private isTermsAcceptedError: boolean = false;
|
||||
private readonly user = new User();
|
||||
|
||||
// tardigrade logic
|
||||
private secret: string = '';
|
||||
private partnerId: string = '';
|
||||
private refUserId: string = '';
|
||||
|
||||
private userId: string = '';
|
||||
private isTermsAccepted: boolean = false;
|
||||
private password: string = '';
|
||||
private repeatedPassword: string = '';
|
||||
|
||||
private fullNameError: string = '';
|
||||
private emailError: string = '';
|
||||
private passwordError: string = '';
|
||||
private repeatedPasswordError: string = '';
|
||||
private isTermsAcceptedError: boolean = false;
|
||||
|
||||
|
||||
private loadingClassName: string = LOADING_CLASSES.LOADING_OVERLAY;
|
||||
|
||||
private readonly auth: AuthApi = new AuthApi();
|
||||
|
||||
mounted(): void {
|
||||
if (this.$route.query.token) {
|
||||
this.secret = this.$route.query.token.toString();
|
||||
@ -51,15 +57,15 @@
|
||||
try {
|
||||
decoded = atob(ids);
|
||||
} catch {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, "Invalid Referral URL.");
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'Invalid Referral URL');
|
||||
this.loadingClassName = LOADING_CLASSES.LOADING_OVERLAY;
|
||||
|
||||
return;
|
||||
}
|
||||
let referralIds = ids ? JSON.parse(decoded) : undefined;
|
||||
if (referralIds) {
|
||||
this.$data.partnerId = referralIds.partnerId;
|
||||
this.$data.refUserId = referralIds.userId;
|
||||
this.user.partnerId = referralIds.partnerId;
|
||||
this.refUserId = referralIds.userId;
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,15 +89,15 @@
|
||||
this.$router.push(ROUTES.LOGIN.path);
|
||||
}
|
||||
public setEmail(value: string): void {
|
||||
this.email = value;
|
||||
this.user.email = value.trim();
|
||||
this.emailError = '';
|
||||
}
|
||||
public setFullName(value: string): void {
|
||||
this.fullName = value;
|
||||
this.user.fullName = value.trim();
|
||||
this.fullNameError = '';
|
||||
}
|
||||
public setShortName(value: string): void {
|
||||
this.shortName = value;
|
||||
this.user.shortName = value.trim();
|
||||
}
|
||||
public setPassword(value: string): void {
|
||||
this.password = value;
|
||||
@ -105,12 +111,12 @@
|
||||
private validateFields(): boolean {
|
||||
let isNoErrors = true;
|
||||
|
||||
if (!this.fullName.trim()) {
|
||||
if (!this.user.fullName.trim()) {
|
||||
this.fullNameError = 'Invalid Name';
|
||||
isNoErrors = false;
|
||||
}
|
||||
|
||||
if (!validateEmail(this.email.trim())) {
|
||||
if (!validateEmail(this.user.email.trim())) {
|
||||
this.emailError = 'Invalid Email';
|
||||
isNoErrors = false;
|
||||
}
|
||||
@ -132,22 +138,21 @@
|
||||
|
||||
return isNoErrors;
|
||||
}
|
||||
private async createUser(): Promise<void> {
|
||||
let user = new User(this.fullName.trim(), this.shortName.trim(), this.email.trim(), this.partnerId);
|
||||
let response = await createUserRequest(user, this.password, this.secret, this.refUserId);
|
||||
if (!response.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, response.errorMessage);
|
||||
this.loadingClassName = LOADING_CLASSES.LOADING_OVERLAY;
|
||||
|
||||
return;
|
||||
}
|
||||
if (response.data) {
|
||||
setUserId(response.data);
|
||||
}
|
||||
// TODO: improve it
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_SUCCESSFUL_REGISTRATION_POPUP);
|
||||
if (this.$refs['register_success_popup'] !== null) {
|
||||
(this.$refs['register_success_popup'] as any).startResendEmailCountdown();
|
||||
private async createUser(): Promise<void> {
|
||||
try {
|
||||
this.userId = await this.auth.create(this.user, this.password , this.secret, this.refUserId);
|
||||
|
||||
setUserId(this.userId);
|
||||
|
||||
// TODO: improve it
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_SUCCESSFUL_REGISTRATION_POPUP);
|
||||
if (this.$refs['register_success_popup'] !== null) {
|
||||
(this.$refs['register_success_popup'] as any).startResendEmailCountdown();
|
||||
}
|
||||
} catch (error) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, error.message);
|
||||
this.loadingClassName = LOADING_CLASSES.LOADING_OVERLAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,84 +1,54 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { usersModule } from '@/store/modules/users';
|
||||
import * as api from '@/api/users';
|
||||
import { changePasswordRequest, deleteAccountRequest, getUserRequest, updateAccountRequest } from '@/api/users';
|
||||
import { USER_MUTATIONS } from '@/store/mutationConstants';
|
||||
import Vuex from 'vuex';
|
||||
import { createLocalVue } from '@vue/test-utils';
|
||||
import { RequestResponse } from '@/types/response';
|
||||
import { User } from '@/types/users';
|
||||
import { UsersApiGql } from '@/api/users';
|
||||
import { makeUsersModule } from '@/store/modules/users';
|
||||
import { USER_MUTATIONS } from '@/store/mutationConstants';
|
||||
import { UpdatedUser, User } from '@/types/users';
|
||||
import { USER_ACTIONS } from '@/utils/constants/actionNames';
|
||||
|
||||
const mutations = usersModule.mutations;
|
||||
const Vue = createLocalVue();
|
||||
const usersApi = new UsersApiGql();
|
||||
const usersModule = makeUsersModule(usersApi);
|
||||
const { UPDATE, GET, CLEAR } = USER_ACTIONS;
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
const store = new Vuex.Store(usersModule);
|
||||
|
||||
describe('mutations', () => {
|
||||
beforeEach(() => {
|
||||
createLocalVue().use(Vuex);
|
||||
});
|
||||
it('Set user info', () => {
|
||||
const state = {
|
||||
user: {
|
||||
fullName: '',
|
||||
shortName: '',
|
||||
email: '',
|
||||
}
|
||||
};
|
||||
it('Set user', () => {
|
||||
const user = new User('1', 'fullName', 'shortName', 'example@email.com');
|
||||
|
||||
const store = new Vuex.Store({state, mutations});
|
||||
store.commit(USER_MUTATIONS.SET_USER, user);
|
||||
|
||||
const user = {
|
||||
fullName: 'fullName',
|
||||
shortName: 'shortName',
|
||||
email: 'email',
|
||||
};
|
||||
|
||||
store.commit(USER_MUTATIONS.SET_USER_INFO, user);
|
||||
|
||||
expect(state.user.email).toBe('email');
|
||||
expect(state.user.fullName).toBe('fullName');
|
||||
expect(state.user.shortName).toBe('shortName');
|
||||
expect(store.state.id).toBe(user.id);
|
||||
expect(store.state.email).toBe(user.email);
|
||||
expect(store.state.fullName).toBe(user.fullName);
|
||||
expect(store.state.shortName).toBe(user.shortName);
|
||||
});
|
||||
|
||||
it('clear user info', () => {
|
||||
const state = {
|
||||
user: {
|
||||
fullName: 'fullName',
|
||||
shortName: 'shortName',
|
||||
email: 'email',
|
||||
}
|
||||
};
|
||||
it('clear user', () => {
|
||||
store.commit(USER_MUTATIONS.CLEAR);
|
||||
|
||||
const store = new Vuex.Store({state, mutations});
|
||||
|
||||
store.commit(USER_MUTATIONS.REVERT_TO_DEFAULT_USER_INFO);
|
||||
|
||||
expect(state.user.email).toBe('');
|
||||
expect(state.user.fullName).toBe('');
|
||||
expect(state.user.shortName).toBe('');
|
||||
expect(store.state.id).toBe('');
|
||||
expect(store.state.email).toBe('');
|
||||
expect(store.state.fullName).toBe('');
|
||||
expect(store.state.shortName).toBe('');
|
||||
});
|
||||
|
||||
it('Update user info', () => {
|
||||
const state = {
|
||||
user: {
|
||||
fullName: '',
|
||||
shortName: '',
|
||||
email: '',
|
||||
}
|
||||
};
|
||||
const user = {
|
||||
fullName: 'fullName',
|
||||
shortName: 'shortName',
|
||||
email: 'email',
|
||||
};
|
||||
it('Update user', () => {
|
||||
const user = new UpdatedUser('fullName', 'shortName');
|
||||
|
||||
const store = new Vuex.Store({state, mutations});
|
||||
store.commit(USER_MUTATIONS.UPDATE_USER, user);
|
||||
|
||||
store.commit(USER_MUTATIONS.UPDATE_USER_INFO, user);
|
||||
|
||||
expect(state.user.email).toBe('email');
|
||||
expect(state.user.fullName).toBe('fullName');
|
||||
expect(state.user.shortName).toBe('shortName');
|
||||
expect(store.state.fullName).toBe(user.fullName);
|
||||
expect(store.state.shortName).toBe(user.shortName);
|
||||
});
|
||||
});
|
||||
|
||||
@ -87,139 +57,74 @@ describe('actions', () => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
it('success update account', async () => {
|
||||
jest.spyOn(api, 'updateAccountRequest').mockReturnValue(
|
||||
Promise.resolve(<RequestResponse<User>>{
|
||||
isSuccess: true, data: {
|
||||
fullName: 'fullName',
|
||||
shortName: 'shortName',
|
||||
email: 'email',
|
||||
}
|
||||
})
|
||||
jest.spyOn(usersApi, 'update').mockReturnValue(
|
||||
Promise.resolve()
|
||||
);
|
||||
const commit = jest.fn();
|
||||
const user = {
|
||||
fullName: '',
|
||||
shortName: '',
|
||||
email: '',
|
||||
};
|
||||
|
||||
const dispatchResponse = await usersModule.actions.updateAccount({commit}, user);
|
||||
const user = new UpdatedUser('fullName1', 'shortName2');
|
||||
|
||||
expect(dispatchResponse.isSuccess).toBeTruthy();
|
||||
expect(commit).toHaveBeenCalledWith(USER_MUTATIONS.UPDATE_USER_INFO, {
|
||||
fullName: 'fullName',
|
||||
shortName: 'shortName',
|
||||
email: 'email',
|
||||
});
|
||||
await store.dispatch(UPDATE, user);
|
||||
|
||||
expect(store.state.fullName).toBe('fullName1');
|
||||
expect(store.state.shortName).toBe('shortName2');
|
||||
});
|
||||
|
||||
it('error update account', async () => {
|
||||
jest.spyOn(api, 'updateAccountRequest').mockReturnValue(
|
||||
Promise.resolve(<RequestResponse<User>>{
|
||||
isSuccess: false
|
||||
})
|
||||
);
|
||||
const commit = jest.fn();
|
||||
const user = {
|
||||
fullName: '',
|
||||
shortName: '',
|
||||
email: '',
|
||||
};
|
||||
it('update throws an error when api call fails', async () => {
|
||||
jest.spyOn(usersApi, 'update').mockImplementation(() => { throw new Error(); });
|
||||
const newUser = new UpdatedUser('', '');
|
||||
const oldUser = store.getters.user;
|
||||
|
||||
const dispatchResponse = await usersModule.actions.updateAccount({commit}, user);
|
||||
|
||||
expect(dispatchResponse.isSuccess).toBeFalsy();
|
||||
expect(commit).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('password change', async () => {
|
||||
jest.spyOn(api, 'changePasswordRequest').mockReturnValue(
|
||||
Promise.resolve(<RequestResponse<null>>{
|
||||
isSuccess: true
|
||||
})
|
||||
);
|
||||
const commit = jest.fn();
|
||||
const updatePasswordModel = {oldPassword: 'o', newPassword: 'n'};
|
||||
|
||||
const requestResponse = await usersModule.actions.changePassword({commit}, updatePasswordModel);
|
||||
|
||||
expect(requestResponse.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
it('delete account', async () => {
|
||||
jest.spyOn(api, 'deleteAccountRequest').mockReturnValue(
|
||||
Promise.resolve(<RequestResponse<null>>{
|
||||
isSuccess: true
|
||||
})
|
||||
);
|
||||
|
||||
const commit = jest.fn();
|
||||
const password = '';
|
||||
|
||||
const dispatchResponse = await usersModule.actions.deleteAccount(commit, password);
|
||||
|
||||
expect(dispatchResponse.isSuccess).toBeTruthy();
|
||||
try {
|
||||
await store.dispatch(UPDATE, newUser);
|
||||
expect(true).toBe(false);
|
||||
} catch (error) {
|
||||
expect(store.state.fullName).toBe(oldUser.fullName);
|
||||
expect(store.state.shortName).toBe(oldUser.shortName);
|
||||
}
|
||||
});
|
||||
|
||||
it('success get user', async () => {
|
||||
jest.spyOn(api, 'getUserRequest').mockReturnValue(
|
||||
Promise.resolve(<RequestResponse<User>>{
|
||||
isSuccess: true,
|
||||
data: {
|
||||
fullName: '',
|
||||
shortName: '',
|
||||
email: '',
|
||||
}
|
||||
})
|
||||
const user = new User('2', 'newFullName', 'newShortName', 'example2@email.com');
|
||||
|
||||
jest.spyOn(usersApi, 'get').mockReturnValue(
|
||||
Promise.resolve(user)
|
||||
);
|
||||
const commit = jest.fn();
|
||||
|
||||
const requestResponse = await usersModule.actions.getUser({commit});
|
||||
await store.dispatch(GET);
|
||||
|
||||
expect(requestResponse.isSuccess).toBeTruthy();
|
||||
expect(store.state.id).toBe(user.id);
|
||||
expect(store.state.shortName).toBe(user.shortName);
|
||||
expect(store.state.fullName).toBe(user.fullName);
|
||||
expect(store.state.email).toBe(user.email);
|
||||
});
|
||||
|
||||
it('error get user', async () => {
|
||||
jest.spyOn(api, 'getUserRequest').mockReturnValue(
|
||||
Promise.resolve(<RequestResponse<User>>{
|
||||
isSuccess: false
|
||||
})
|
||||
);
|
||||
const commit = jest.fn();
|
||||
it('get throws an error when api call fails', async () => {
|
||||
const user = store.getters.user;
|
||||
jest.spyOn(usersApi, 'get').mockImplementation(() => { throw new Error(); });
|
||||
|
||||
const requestResponse = await usersModule.actions.getUser({commit});
|
||||
|
||||
expect(requestResponse.isSuccess).toBeFalsy();
|
||||
try {
|
||||
await store.dispatch(GET);
|
||||
expect(true).toBe(false);
|
||||
} catch (error) {
|
||||
expect(store.state.fullName).toBe(user.fullName);
|
||||
expect(store.state.shortName).toBe(user.shortName);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('getters', () => {
|
||||
it('user model', function () {
|
||||
const state = {
|
||||
user: {
|
||||
fullName: 'fullName',
|
||||
shortName: 'shortName',
|
||||
email: 'email',
|
||||
}
|
||||
};
|
||||
const retrievedUser = store.getters.user;
|
||||
|
||||
const retrievedUser = usersModule.getters.user(state);
|
||||
|
||||
expect(retrievedUser.fullName).toBe('fullName');
|
||||
expect(retrievedUser.shortName).toBe('shortName');
|
||||
expect(retrievedUser.email).toBe('email');
|
||||
expect(retrievedUser.id).toBe(store.state.id);
|
||||
expect(retrievedUser.fullName).toBe(store.state.fullName);
|
||||
expect(retrievedUser.shortName).toBe(store.state.shortName);
|
||||
expect(retrievedUser.email).toBe(store.state.email);
|
||||
});
|
||||
|
||||
it('user name', function () {
|
||||
const state = {
|
||||
user: {
|
||||
fullName: 'John',
|
||||
shortName: 'Doe'
|
||||
}
|
||||
};
|
||||
const retrievedUserName = store.getters.userName;
|
||||
|
||||
const retrievedUserName = usersModule.getters.userName(state);
|
||||
|
||||
expect(retrievedUserName).toBe('John Doe');
|
||||
expect(retrievedUserName).toBe(store.state.getFullName());
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user