web/satellite: take project amount limit from db instead of config

WHAT:
Now project amount limit is taken from users db instead of config. But if db value is 0 then default config value will be used instead.

WHY:
this will allow us to change user's project limit by changing db value.

Change-Id: I9edcd0bf9eaae5fe40e90a44cac82d9ce8519274
This commit is contained in:
VitaliiShpital 2020-10-05 20:33:16 +03:00 committed by Vitalii Shpital
parent be84616e69
commit 59d85aab5b
17 changed files with 62 additions and 39 deletions

View File

@ -208,11 +208,12 @@ func (a *Auth) GetAccount(w http.ResponseWriter, r *http.Request) {
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)
var user struct { var user struct {
ID uuid.UUID `json:"id"` ID uuid.UUID `json:"id"`
FullName string `json:"fullName"` FullName string `json:"fullName"`
ShortName string `json:"shortName"` ShortName string `json:"shortName"`
Email string `json:"email"` Email string `json:"email"`
PartnerID uuid.UUID `json:"partnerId"` PartnerID uuid.UUID `json:"partnerId"`
ProjectLimit int `json:"projectLimit"`
} }
auth, err := console.GetAuth(ctx) auth, err := console.GetAuth(ctx)
@ -226,6 +227,7 @@ func (a *Auth) GetAccount(w http.ResponseWriter, r *http.Request) {
user.Email = auth.User.Email user.Email = auth.User.Email
user.ID = auth.User.ID user.ID = auth.User.ID
user.PartnerID = auth.User.PartnerID user.PartnerID = auth.User.PartnerID
user.ProjectLimit = auth.User.ProjectLimit
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(&user) err = json.NewEncoder(w).Encode(&user)

View File

@ -125,7 +125,18 @@ export class AuthHttpApi {
const path = `${this.ROOT_PATH}/account`; const path = `${this.ROOT_PATH}/account`;
const response = await this.http.get(path); const response = await this.http.get(path);
if (response.ok) { if (response.ok) {
return await response.json(); const userResponse = await response.json();
return new User(
userResponse.id,
userResponse.fullName,
userResponse.shortName,
userResponse.email,
userResponse.partner,
userResponse.partnerId,
userResponse.password,
userResponse.projectLimit,
);
} }
if (response.status === 401) { if (response.status === 401) {

View File

@ -183,7 +183,7 @@ export default class BillingArea extends Vue {
* Indicates if user has own project. * Indicates if user has own project.
*/ */
public get userHasOwnProject(): boolean { public get userHasOwnProject(): boolean {
return this.$store.getters.userProjectsCount > 0; return this.$store.getters.projectsCount > 0;
} }
/** /**

View File

@ -103,7 +103,7 @@ export default class AddCardForm extends Vue {
* Indicates if user has own project. * Indicates if user has own project.
*/ */
private get userHasOwnProject(): boolean { private get userHasOwnProject(): boolean {
return this.$store.getters.userProjectsCount > 0; return this.$store.getters.projectsCount > 0;
} }
} }
</script> </script>

View File

@ -105,7 +105,7 @@ export default class AddStorjForm extends Vue {
* Indicates if user has own project. * Indicates if user has own project.
*/ */
private get userHasOwnProject(): boolean { private get userHasOwnProject(): boolean {
return this.$store.getters.userProjectsCount > 0; return this.$store.getters.projectsCount > 0;
} }
/** /**

View File

@ -124,7 +124,7 @@ export default class TokenDepositSelection extends Vue {
* Returns payment options depending on user having his own project. * Returns payment options depending on user having his own project.
*/ */
public get options(): PaymentAmountOption[] { public get options(): PaymentAmountOption[] {
if (this.$store.getters.userProjectsCount === 0 && this.noCreditCards) { if (this.$store.getters.projectsCount === 0 && this.noCreditCards) {
return this.initialPaymentOptions; return this.initialPaymentOptions;
} }

View File

@ -90,6 +90,7 @@ export default class VButton extends Vue {
.disabled { .disabled {
background-color: #dadde5 !important; background-color: #dadde5 !important;
border-color: #dadde5 !important; border-color: #dadde5 !important;
pointer-events: none !important;
.label { .label {
color: #acb0bc !important; color: #acb0bc !important;

View File

@ -30,7 +30,6 @@ import ExpandIcon from '@/../static/images/common/BlackArrowExpand.svg';
import { RouteConfig } from '@/router'; import { RouteConfig } from '@/router';
import { PROJECTS_ACTIONS } from '@/store/modules/projects'; import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames'; import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import { MetaUtils } from '@/utils/meta';
import ProjectDropdown from './ProjectDropdown.vue'; import ProjectDropdown from './ProjectDropdown.vue';
@ -111,9 +110,7 @@ export default class ProjectSelection extends Vue {
* Indicates if project count limit is reached. * Indicates if project count limit is reached.
*/ */
private get isProjectLimitReached(): boolean { private get isProjectLimitReached(): boolean {
const defaultProjectLimit: number = parseInt(MetaUtils.getMetaContent('default-project-limit')); return this.$store.getters.projectsCount >= this.$store.getters.user.projectLimit;
return this.$store.getters.userProjectsCount >= defaultProjectLimit;
} }
} }
</script> </script>

View File

@ -76,7 +76,6 @@ import {
} from '@/utils/constants/actionNames'; } from '@/utils/constants/actionNames';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames'; import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { LocalData } from '@/utils/localData'; import { LocalData } from '@/utils/localData';
import { MetaUtils } from '@/utils/meta';
@Component({ @Component({
components: { components: {
@ -183,8 +182,7 @@ export default class NewProjectPopup extends Vue {
this.$store.dispatch(PROJECTS_ACTIONS.SELECT, this.createdProjectId); this.$store.dispatch(PROJECTS_ACTIONS.SELECT, this.createdProjectId);
LocalData.setSelectedProjectId(this.createdProjectId); LocalData.setSelectedProjectId(this.createdProjectId);
const defaultProjectLimit: number = parseInt(MetaUtils.getMetaContent('default-project-limit')); if (this.$store.getters.projectsCount >= this.$store.getters.user.projectLimit) {
if (this.$store.getters.userProjectsCount >= defaultProjectLimit) {
this.$store.dispatch(APP_STATE_ACTIONS.HIDE_CREATE_PROJECT_BUTTON); this.$store.dispatch(APP_STATE_ACTIONS.HIDE_CREATE_PROJECT_BUTTON);
} }
} }

View File

@ -41,8 +41,8 @@ export default class ProjectDashboard extends Vue {
return; return;
} }
const defaultProjectLimit: number = parseInt(MetaUtils.getMetaContent('default-project-limit')); const projectLimit: number = this.$store.getters.user.projectLimit;
if (defaultProjectLimit && this.$store.getters.userProjectsCount < defaultProjectLimit) { if (projectLimit && this.$store.getters.projectsCount < projectLimit) {
this.$store.dispatch(APP_STATE_ACTIONS.SHOW_CREATE_PROJECT_BUTTON); this.$store.dispatch(APP_STATE_ACTIONS.SHOW_CREATE_PROJECT_BUTTON);
} }

View File

@ -182,7 +182,7 @@ export function makeProjectsModule(api: ProjectsApi): StoreModule<ProjectsState>
}); });
}, },
selectedProject: (state: ProjectsState): Project => state.selectedProject, selectedProject: (state: ProjectsState): Project => state.selectedProject,
userProjectsCount: (state: ProjectsState, getters: any): number => { projectsCount: (state: ProjectsState, getters: any): number => {
let projectsCount: number = 0; let projectsCount: number = 0;
state.projects.map((project: Project) => { state.projects.map((project: Project) => {

View File

@ -3,6 +3,7 @@
import { StoreModule } from '@/store'; import { StoreModule } from '@/store';
import { UpdatedUser, User, UsersApi } from '@/types/users'; import { UpdatedUser, User, UsersApi } from '@/types/users';
import { MetaUtils } from '@/utils/meta';
export const USER_ACTIONS = { export const USER_ACTIONS = {
UPDATE: 'updateUser', UPDATE: 'updateUser',
@ -43,6 +44,16 @@ export function makeUsersModule(api: UsersApi): StoreModule<User> {
state.shortName = user.shortName; state.shortName = user.shortName;
state.fullName = user.fullName; state.fullName = user.fullName;
state.partnerId = user.partnerId; state.partnerId = user.partnerId;
if (user.projectLimit === 0) {
const limitFromConfig = MetaUtils.getMetaContent('default-project-limit');
state.projectLimit = parseInt(limitFromConfig);
return;
}
state.projectLimit = user.projectLimit;
}, },
[CLEAR](state: User): void { [CLEAR](state: User): void {
@ -51,6 +62,7 @@ export function makeUsersModule(api: UsersApi): StoreModule<User> {
state.shortName = ''; state.shortName = '';
state.fullName = ''; state.fullName = '';
state.partnerId = ''; state.partnerId = '';
state.projectLimit = 1;
}, },
[UPDATE_USER](state: User, user: UpdatedUser): void { [UPDATE_USER](state: User, user: UpdatedUser): void {

View File

@ -33,6 +33,7 @@ export class User {
public partner: string = '', public partner: string = '',
public partnerId: string = '', public partnerId: string = '',
public password: string = '', public password: string = '',
public projectLimit: number = 0,
) {} ) {}
public getFullName(): string { public getFullName(): string {

View File

@ -26,9 +26,9 @@
<VInfoBar <VInfoBar
v-if="isProjectLimitInfoBarShown" v-if="isProjectLimitInfoBarShown"
is-blue="true" is-blue="true"
:first-value="`You have used ${userProjectsCount}`" :first-value="`You have used ${projectsCount}`"
first-description="of your" first-description="of your"
:second-value="defaultProjectLimit" :second-value="projectLimit"
second-description="available projects." second-description="available projects."
:link="projectLimitsIncreaseRequestURL" :link="projectLimitsIncreaseRequestURL"
link-label="Request Project Limit Increase" link-label="Request Project Limit Increase"
@ -232,28 +232,31 @@ export default class DashboardArea extends Vue {
public get isBillingInfoBarShown(): boolean { public get isBillingInfoBarShown(): boolean {
const isBillingPage = this.$route.name === RouteConfig.Billing.name; const isBillingPage = this.$route.name === RouteConfig.Billing.name;
return isBillingPage && this.userProjectsCount > 0; return isBillingPage && this.projectsCount > 0;
} }
/** /**
* Indicates if project limit info bar is shown. * Indicates if project limit info bar is shown.
*/ */
public get isProjectLimitInfoBarShown(): boolean { public get isProjectLimitInfoBarShown(): boolean {
return this.userProjectsCount === this.defaultProjectLimit && this.$route.name === RouteConfig.ProjectDashboard.name; return this.$route.name === RouteConfig.ProjectDashboard.name;
} }
/** /**
* Returns user's projects count. * Returns user's projects count.
*/ */
public get userProjectsCount(): number { public get projectsCount(): number {
return this.$store.getters.userProjectsCount; return this.$store.getters.projectsCount;
} }
/** /**
* Returns default project limit from config. * Returns project limit from store.
*/ */
public get defaultProjectLimit(): number { public get projectLimit(): number {
return parseInt(MetaUtils.getMetaContent('default-project-limit')); const projectLimit: number = this.$store.getters.user.projectLimit;
if (projectLimit < this.projectsCount) return this.projectsCount;
return projectLimit;
} }
/** /**
@ -263,13 +266,6 @@ export default class DashboardArea extends Vue {
return MetaUtils.getMetaContent('project-limits-increase-request-url'); return MetaUtils.getMetaContent('project-limits-increase-request-url');
} }
/**
* Returns general request url from config.
*/
public get generalRequestURL(): string {
return MetaUtils.getMetaContent('general-request-url');
}
/** /**
* Returns formatted string of remaining storage. * Returns formatted string of remaining storage.
*/ */

View File

@ -5,22 +5,27 @@ import Vuex from 'vuex';
import ProjectDashboard from '@/components/project/ProjectDashboard.vue'; import ProjectDashboard from '@/components/project/ProjectDashboard.vue';
import { appStateModule } from '@/store/modules/appState';
import { makeProjectsModule, PROJECTS_MUTATIONS } from '@/store/modules/projects'; import { makeProjectsModule, PROJECTS_MUTATIONS } from '@/store/modules/projects';
import { makeUsersModule } from '@/store/modules/users';
import { Project } from '@/types/projects'; import { Project } from '@/types/projects';
import { SegmentioPlugin } from '@/utils/plugins/segment'; import { SegmentioPlugin } from '@/utils/plugins/segment';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import { ProjectsApiMock } from '../mock/api/projects'; import { ProjectsApiMock } from '../mock/api/projects';
import { UsersApiMock } from '../mock/api/users';
const segmentioPlugin = new SegmentioPlugin(); const segmentioPlugin = new SegmentioPlugin();
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
localVue.use(segmentioPlugin); localVue.use(segmentioPlugin);
const usersApi = new UsersApiMock();
const usersModule = makeUsersModule(usersApi);
const projectsApi = new ProjectsApiMock(); const projectsApi = new ProjectsApiMock();
const projectsModule = makeProjectsModule(projectsApi); const projectsModule = makeProjectsModule(projectsApi);
const store = new Vuex.Store({ modules: { projectsModule }}); const store = new Vuex.Store({ modules: { appStateModule, usersModule, projectsModule }});
const project = new Project('id', 'test', 'test', 'test', 'ownedId', false); const project = new Project('id', 'test', 'test', 'test', 'ownedId', false);
describe('ProjectDashboard.vue', () => { describe('ProjectDashboard.vue', () => {

View File

@ -38,7 +38,7 @@ localVue.use(notificationPlugin);
const usersApi = new UsersApiMock(); const usersApi = new UsersApiMock();
const projectsApi = new ProjectsApiMock(); const projectsApi = new ProjectsApiMock();
usersApi.setMockUser(new User('1', '2', '3', '4', '5')); usersApi.setMockUser(new User('1', '2', '3', '4', '5', '6', '7', 1));
projectsApi.setMockProjects([]); projectsApi.setMockProjects([]);
const usersModule = makeUsersModule(usersApi); const usersModule = makeUsersModule(usersApi);

View File

@ -11,7 +11,7 @@ exports[`Dashboard renders correctly when data is loaded 1`] = `
<div class="dashboard__wrap__main-area__content"> <div class="dashboard__wrap__main-area__content">
<div class="dashboard__wrap__main-area__content__bar-area"> <div class="dashboard__wrap__main-area__content__bar-area">
<!----> <!---->
<!----> <vinfobar-stub firstvalue="You have used 0" secondvalue="1" firstdescription="of your" seconddescription="available projects." link="" linklabel="Request Project Limit Increase" path="" isblue="true"></vinfobar-stub>
</div> </div>
<router-view-stub name="default"></router-view-stub> <router-view-stub name="default"></router-view-stub>
</div> </div>