Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed admin settings permissions #2794

Closed
wants to merge 49 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
85920aa
New payment details implementation
AndriiMysko Feb 8, 2023
aa51d29
Fix tests
AndriiMysko Feb 9, 2023
9cfef7e
Antifraud for v1 plans
AndriiMysko Feb 9, 2023
6376286
Adjust tests
AndriiMysko Feb 10, 2023
c975f4c
Merge branch 'payment_method_tab_am' into new_user_journey_dev
AndriiMysko Feb 10, 2023
5de968c
fix for lack of first_sync for assembla
AndriiMysko Feb 10, 2023
62e6d28
added hosted billing help
AndriiMysko Feb 10, 2023
d97e061
Add the new macOS information section in select-plan and modify billi…
Jullianos Jan 31, 2023
105949e
Adjust manual and github plans view
AndriiMysko Feb 13, 2023
6e2a22a
Fix local registration checkbox
AndriiMysko Feb 16, 2023
773022e
ui updates
AndriiMysko Feb 23, 2023
6bea8b3
redirection attempt, wizard fix, trial plan desc
AndriiMysko Feb 28, 2023
02ad650
ui updates
AndriiMysko Mar 9, 2023
6ae4961
sync subscriptions on first_syn
AndriiMysko Mar 13, 2023
21cd028
redirect from ghapp installation to firstsync
AndriiMysko Mar 15, 2023
4d42873
style fixes,profile menu update,fix for company
gbarc80 Mar 16, 2023
1c2bfbb
tests update
gbarc80 Mar 16, 2023
c3d6c3c
ui updates
gbarc80 Mar 20, 2023
30201a8
ui updates
gbarc80 Mar 20, 2023
028299d
redirection updates, typos fixed
gbarc80 Mar 21, 2023
4fa677a
ui updates - plan, wizard, activation
gbarc80 Mar 23, 2023
b105838
coupon
gbarc80 Mar 23, 2023
c33ec59
installation redirections, email banner update
gbarc80 Mar 24, 2023
edf92a0
random ui updates
gbarc80 Mar 24, 2023
6340e63
lint
gbarc80 Mar 24, 2023
fee0e23
total price hide
gbarc80 Mar 24, 2023
09cf0e4
empty invoices field, installation_id fix
gbarc80 Mar 27, 2023
ee76cf6
radio color,mail banner, double badge
gbarc80 Mar 28, 2023
4b41c15
ui fixes - review 03.28
gbarc80 Mar 30, 2023
80313d7
sync popup improvement
gbarc80 Mar 30, 2023
24c8644
billing css merge
gbarc-dt May 22, 2023
167d2fe
activation button fix
gbarc-dt May 24, 2023
ef0700b
lint
gbarc-dt May 24, 2023
120be38
user roles wip
gbarc-dt May 26, 2023
3f31080
Merge branch 'master' into new_user_journey_dev
murtaza-swati May 30, 2023
6d31388
logs, settings, caches
gbarc-dt Jun 7, 2023
a654110
fixed the condition for settings
gbarc-dt Jun 7, 2023
8ca05ca
perm fixes/test fixes
gbarc-dt Jun 9, 2023
5b530c3
usage banner fix, settings from profile access check
gbarc-dt Jun 23, 2023
c65308e
tests
gbarc-dt Jun 23, 2023
4c54695
Merge branch 'new_user_journey_dev' into dt-userroles-prd
gbarc-dt Jul 14, 2023
9b2e683
selected plan up
gbarc-dt Jul 14, 2023
c5fdd38
lint
gbarc-dt Jul 14, 2023
8237b79
lint
gbarc-dt Jul 14, 2023
5e1c004
activate update
gbarc-dt Jul 14, 2023
333acab
merge master
murtaza-swati Oct 28, 2023
a61c160
added missing check
murtaza-swati Oct 28, 2023
4230701
Merge branch 'master' into dt-userroles-prd
murtaza-swati Dec 14, 2023
3817483
fixed admin settings permissions
gbarc-dt Dec 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/components/billing/authorization.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export default Component.extend({
requiresSource: equal('subscription.paymentIntent.status', 'requires_source'),
lastPaymentIntentError: reads('subscription.paymentIntent.last_payment_error'),
retryAuthorizationClientSecret: reads('subscription.paymentIntent.client_secret'),
hasSubscriptionPermissions: reads('account.hasSubscriptionPermissions'),
notChargeInvoiceSubscription: not('subscription.chargeUnpaidInvoices.lastSuccessful.value'),
freeV2Plan: equal('subscription.plan.startingPrice', 0),
isSubscribed: reads('subscription.isSubscribed'),
Expand All @@ -32,6 +31,10 @@ export default Component.extend({
canCancelSubscription: computed('isSubscribed', 'hasSubscriptionPermissions', 'freeV2Plan', 'isTrial', function () {
return this.isSubscribed && this.hasSubscriptionPermissions && !this.freeV2Plan && !this.isTrial;
}),

hasSubscriptionPermissions: computed('account.hasSubscriptionPermissions', 'account.permissions', function () {
return this.account.hasSubscriptionPermissions && (!this.account.isOrganization || this.account.permissions.plan_create);
}),
cancelSubscriptionLoading: reads('subscription.cancelSubscription.isRunning'),
isTrial: reads('subscription.plan.isTrial'),
isLoading: or('accounts.fetchSubscriptions.isRunning', 'accounts.fetchV2Subscriptions.isRunning',
Expand Down
8 changes: 8 additions & 0 deletions app/components/billing/payment-details-tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export default Component.extend({
metrics: service(),

countries,

model: reads('activeModel'),
states: computed('country', function () {
const { country } = this;

Expand All @@ -37,6 +39,12 @@ export default Component.extend({
isV2SubscriptionEmpty: empty('v2subscription'),
isSubscriptionEmpty: empty('v1subscription'),
isSubscriptionsEmpty: and('isSubscriptionEmpty', 'isV2SubscriptionEmpty'),
canViewBilling: computed('model', function () {
return !this.account.isOrganization || this.account.permissions.billing_view;
}),
canEditBilling: computed('model', function () {
return !this.account.isOrganization || this.account.permissions.billing_update;
}),
hasV2Subscription: not('isV2SubscriptionEmpty'),
subscription: computed('v1subscription', 'v2subscription', function () {
return this.isV2SubscriptionEmpty ? this.get('v1subscription') : this.get('v2subscription');
Expand Down
3 changes: 3 additions & 0 deletions app/components/billing/select-plan.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export default Component.extend({
return false;
}
}),
hasPlanChangePermission: computed('account', function () {
return !this.account.isOrganization || this.account.permissions.plan_create;
}),

save: task(function* () {
if (this.next.perform) {
Expand Down
11 changes: 10 additions & 1 deletion app/components/github-apps-repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,18 @@ export default Component.extend({
return this.user && vcsLinks.accessSettingsUrl(this.user.vcsType, { owner: this.user.login });
}),

hasActivatePermission: computed('permissions.all', 'repository', function () {
let repo = this.repository;
let forRepo = (repo.owner.id == this.user.id && repo.ownerType == 'user') ||
((repo.shared || repo.ownerType != 'user') && repo.permissions.activate);
return forRepo;
}),

hasSettingsPermission: computed('permissions.all', 'repository', function () {
let repo = this.repository;
return this.permissions.hasPushPermission(repo);
let forRepo = (repo.owner.id == this.user.id && repo.ownerType == 'user') ||
((repo.shared || repo.ownerType != 'user') && repo.permissions.settings_read);
return this.permissions.hasPushPermission(repo) && forRepo;
}),

hasEmailSubscription: computed('repository', 'repository.emailSubscribed', function () {
Expand Down
14 changes: 11 additions & 3 deletions app/components/log-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,13 @@ export default Component.extend({
return this.permissions.hasPermission(repo);
}),

canRemoveLog: computed('job', 'job.canRemoveLog', 'hasPermission', function () {
canRemoveLog: computed('job', 'job.canRemoveLog', 'hasPermission', 'currentUser', function () {
let job = this.job;
let canRemoveLog = this.get('job.canRemoveLog');
let hasPermission = this.hasPermission;
let access = this.currentUser && this.currentUser.hasPermissionToRepo(this.get('job.repo'), 'log_delete');
if (job) {
return canRemoveLog && hasPermission;
return canRemoveLog && hasPermission && access;
}
}),

Expand All @@ -247,7 +248,14 @@ export default Component.extend({
},

toggleLog() {
this.toggleProperty('logIsVisible');
let access = this.currentUser && this.currentUser.hasPermissionToRepo(this.get('job.repo'), 'log_view');
if (access) {
this.toggleProperty('logIsVisible');
} else {
if (this.logIsVisible) {
this.toggleProperty('logIsVisible');
}
}
},

toggleRemoveLogModal() {
Expand Down
52 changes: 38 additions & 14 deletions app/components/profile-nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,23 +64,47 @@ export default Component.extend({

isOrganization: reads('model.isOrganization'),
hasAdminPermissions: reads('model.permissions.admin'),
hasPlanViewPermissions: reads('model.permissions.plan_view'),
hasPlanUsagePermissions: reads('model.permissions.plan_usage'),
hasPlanCreatePermissions: reads('model.permissions.plan_create'),
hasBillingViewPermissions: reads('model.permissions.billing_view'),
hasInvoicesViewPermissions: reads('model.permissions.plan_invoices'),
hasSettingsReadPermissions: reads('model.permissions.settings_read'),
hasSettingsCreatePermissions: reads('model.permissions.settings_create'),
isOrganizationAdmin: and('isOrganization', 'hasAdminPermissions'),
showOrganizationSettings: and('isOrganizationAdmin', 'isProVersion'),

showSubscriptionTab: computed('features.enterpriseVersion', 'model.isAssembla', 'model.isUser', function () {
const isAssemblaUser = this.model.isUser && this.model.isAssembla;
const isEnterprise = this.features.get('enterpriseVersion');
return !isEnterprise && !isAssemblaUser && !!billingEndpoint;
showOrganizationSettings: computed('isOrganizationAdmin', 'isProVersion', 'hasSettingsCreatePermissions', function () {
const forOrganization = !this.isOrganization || this.hasSettingsCreatePermissions;
return this.isProVersion && forOrganization;
}),
showPaymentDetailsTab: computed('showSubscriptionTab', 'isOrganization', 'isOrganizationAdmin', 'model.isNotGithubOrManual', function () {
if (this.isOrganization) {
return this.showSubscriptionTab && this.isOrganizationAdmin && this.model.get('isNotGithubOrManual');
} else {
return this.showSubscriptionTab && this.model.get('isNotGithubOrManual');
}

showSubscriptionTab: computed('features.enterpriseVersion', 'hasPlanViewPermissions',
'hasPlanCreatePermissions', 'model.isAssembla', 'model.isUser',
'isOrganization', function () {
const forOrganization = !this.isOrganization ||
((this.model.hasSubscription || this.model.hasV2Subscription) && !!this.hasPlanViewPermissions) ||
!!this.hasPlanCreatePermissions;

const isAssemblaUser = this.model.isUser && this.model.isAssembla;
const isEnterprise = this.features.get('enterpriseVersion');
return !isEnterprise && !isAssemblaUser && !!billingEndpoint && !!forOrganization;
}),
showPaymentDetailsTab: computed('showSubscriptionTab', 'isOrganization', 'isOrganizationAdmin',
'hasBillingViewPermissions', 'hasInvoicesViewPermissions', 'model.isNotGithubOrManual', function () {
if (this.isOrganization) {
const forOrganization = !this.isOrganization || this.hasBillingViewPermissions || this.hasInvoicesViewPermissions;

return this.showSubscriptionTab && this.model.get('isNotGithubOrManual') && (this.isOrganizationAdmin || forOrganization);
} else {
return this.showSubscriptionTab && this.model.get('isNotGithubOrManual');
}
}),
showPlanUsageTab: computed('showSubscriptionTab', 'model.hasCredits', 'hasPlanUsagePermissions', function () {
const forOrganization = !this.isOrganization || this.hasPlanUsagePermissions;
return this.showSubscriptionTab && this.model.hasCredits && forOrganization;
}),
showPlanUsageTab: and('showSubscriptionTab', 'model.hasCredits'),
usersUsage: computed('account.allowance.userUsage', 'addonUsage', function () {

usersUsage: computed('account.allowance.userUsage', 'addonUsage', 'hasPlanUsagePermissions', function () {
// const forOrganization = !this.isOrganization || this.hasPlanUsagePermissions;
const userUsage = this.model.allowance.get('userUsage');
if (userUsage === undefined) {
return true;
Expand Down
28 changes: 25 additions & 3 deletions app/components/repo-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default Component.extend({
userHasPermissionForRepo: computed('repo.id', 'user', 'user.permissions.[]', function () {
let repo = this.repo;
let user = this.user;

if (user && repo) {
return user.hasAccessToRepo(repo);
}
Expand All @@ -58,6 +59,27 @@ export default Component.extend({
return user.hasPushAccessToRepo(repo);
}
}),
userHasCancelPermissionForRepo: computed('repo.id', 'user', function () {
let repo = this.repo;
let user = this.user;
if (user && repo) {
return user.hasPermissionToRepo(repo, 'build_cancel');
}
}),
userHasRestartPermissionForRepo: computed('repo.id', 'user', function () {
let repo = this.repo;
let user = this.user;
if (user && repo) {
return user.hasPermissionToRepo(repo, 'build_restart');
}
}),
userHasDebugPermissionForRepo: computed('repo.id', 'user', function () {
let repo = this.repo;
let user = this.user;
if (user && repo) {
return user.hasPermissionToRepo(repo, 'build_debug');
}
}),

canOwnerBuild: reads('repo.canOwnerBuild'),
ownerRoMode: reads('repo.owner.ro_mode'),
Expand All @@ -68,9 +90,9 @@ export default Component.extend({

showPriority: true,
showPrioritizeBuildModal: false,
canCancel: and('userHasPullPermissionForRepo', 'item.canCancel'),
canRestart: and('userHasPullPermissionForRepo', 'item.canRestart'),
canDebug: and('userHasPushPermissionForRepo', 'item.canDebug'),
canCancel: and('userHasCancelPermissionForRepo', 'item.canCancel'),
canRestart: and('userHasRestartPermissionForRepo', 'item.canRestart'),
canDebug: and('userHasDebugPermissionForRepo', 'item.canDebug'),
isHighPriority: or('item.priority', 'item.build.priority'),
isNotAlreadyHighPriority: not('isHighPriority'),
hasPrioritizePermission: or('item.permissions.prioritize', 'item.build.permissions.prioritize'),
Expand Down
13 changes: 9 additions & 4 deletions app/components/repo-show-tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ export default Component.extend({

displaySettingsLink: computed('permissions.all', 'repo', function () {
let repo = this.repo;
return this.permissions.hasPushPermission(repo);
const forRepo = repo.permissions.settings_read;

return this.permissions.hasPushPermission(repo) && forRepo;
}),

displayCachesLink: computed('permissions.all', 'repo', function () {
let repo = this.repo;
return this.permissions.hasPushPermission(repo) && config.endpoints.caches;
const forRepo = repo.permissions.cache_view;

return this.permissions.hasPushPermission(repo) && config.endpoints.caches && forRepo;
}),

displayStatusImages: computed('permissions.all', 'repo', function () {
Expand All @@ -49,11 +53,12 @@ export default Component.extend({
let canTriggerBuild = this.get('repo.permissions.create_request');
let enterprise = this.get('features.enterpriseVersion');
let pro = this.get('features.proVersion');
const forRepo = this.repo.permissions.build_create;

if (enterprise || pro) {
return canTriggerBuild;
return canTriggerBuild && forRepo;
}
return canTriggerBuild && migrationStatus !== 'migrated';
return canTriggerBuild && migrationStatus !== 'migrated' && forRepo;
}
),

Expand Down
4 changes: 3 additions & 1 deletion app/models/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ export default Model.extend(DurationCalculations, {
return !isEmpty(jobs.filterBy('canCancel'));
}),

canRestart: alias('isFinished'),
canRestart: computed('isFinished', function () {
return this.isFinished;
}),

cancel() {
const url = `/build/${this.id}/cancel`;
Expand Down
13 changes: 9 additions & 4 deletions app/models/job.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import Model, { attr, belongsTo } from '@ember-data/model';
import { observer, computed } from '@ember/object';
import { alias, and, equal, not, reads } from '@ember/object/computed';
import { alias, and, equal, reads } from '@ember/object/computed';
import { inject as service } from '@ember/service';
import { isEqual } from '@ember/utils';
import { getOwner } from '@ember/application';
Expand Down Expand Up @@ -154,11 +154,13 @@ export default Model.extend(DurationCalculations, DurationAttributes, {
canCancel: computed('isFinished', 'state', function () {
let isFinished = this.isFinished;
let state = this.state;
// not(isFinished) is insufficient since it will be true when state is undefined.
return !isFinished && !!state;
}),

canRestart: alias('isFinished'),
canRestart: computed('isFinished', function () {
let isFinished = this.isFinished;
return isFinished;
}),
canDebug: and('isFinished', 'repo.private'),

cancel() {
Expand Down Expand Up @@ -234,7 +236,10 @@ export default Model.extend(DurationCalculations, DurationAttributes, {
}
}),

canRemoveLog: not('log.removed'),
canRemoveLog: computed('log.removed', function () {
let removed = !!this.log.removed;
return !removed;
}),

slug: computed('repo.slug', 'number', function () {
let slug = this.get('repo.slug');
Expand Down
3 changes: 3 additions & 0 deletions app/models/repo.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ const Repo = VcsEntity.extend({

fetchSettings: task(function* () {
if (!this.auth.signedIn) return {};

const hasPermissions = this.permissions.settings_read;
if (hasPermissions === false) return {};
try {
const response = yield this.api.get(`/repo/${this.id}/settings`);
return this._convertV3SettingsToV2(response.settings);
Expand Down
7 changes: 7 additions & 0 deletions app/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ export default Owner.extend({
}
},

hasPermissionToRepo(repo, permission) {
let permissions = repo.get ? repo.get('permissions') : null;
if (permissions) {
return permissions[permission] || false;
}
},

sync(isOrganization) {
this.set('isSyncing', true);
this.set('applyFilterRepos', !isOrganization);
Expand Down
9 changes: 9 additions & 0 deletions app/routes/caches.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ export default TravisRoute.extend({
return this.controllerFor('repo').activate('caches');
},

beforeModel() {
const repo = this.modelFor('repo');
if (!repo.permissions.cache_view) {
this.transitionTo('repo.index');
this.flashes.error('Your permissions are insufficient to access this repository\'s cache');
}
},


model() {
const repo = this.modelFor('repo');
const url = `/repo/${repo.get('id')}/caches`;
Expand Down
2 changes: 1 addition & 1 deletion app/routes/organization/billing.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import AccountBillingMixin from 'travis/mixins/route/account/billing';
export default TravisRoute.extend(AccountBillingMixin, {
model() {
const organization = this.modelFor('organization');
if (organization.permissions && organization.permissions.admin !== true) {
if (organization.permissions && organization.permissions.plan_view !== true) {
this.transitionTo('organization.repositories', organization);
}
return hash({
Expand Down
2 changes: 1 addition & 1 deletion app/routes/organization/plan_usage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { hash } from 'rsvp';
export default TravisRoute.extend(AccountPlanUsageMixin, {
model() {
const organization = this.modelFor('organization');
if (organization.permissions && organization.permissions.admin !== true) {
if (organization.permissions && organization.permissions.plan_usage !== true) {
this.transitionTo('organization.repositories', organization);
}
return hash({
Expand Down
3 changes: 0 additions & 3 deletions app/routes/organization/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ export default TravisRoute.extend({

model() {
const organization = this.modelFor('organization');
if (organization.permissions.admin !== true) {
this.transitionTo('organization.repositories', organization);
}
const preferences = this.store.query('preference', { organization_id: organization.id });
return hash({ organization, preferences });
},
Expand Down
3 changes: 1 addition & 2 deletions app/routes/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ export default TravisRoute.extend({

beforeModel() {
const repo = this.modelFor('repo');
const hasPushPermission = this.permissions.hasPushPermission(repo);
if (!hasPushPermission) {
if (!repo.permissions.settings_read) {
this.transitionTo('repo.index');
this.flashes.error('Your permissions are insufficient to access this repository\'s settings');
}
Expand Down
Loading