diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-27 09:12:29 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-27 09:12:29 +0300 |
commit | 2af65f9153baf358bfc6acdd8de9652b39264497 (patch) | |
tree | d6af38edbdded9835907da8da5dc11bca09c7749 /app | |
parent | 39c9abe4fe410ac402d57a364bf89938a2067315 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
20 files changed, 277 insertions, 25 deletions
diff --git a/app/assets/javascripts/admin/users/components/actions/index.js b/app/assets/javascripts/admin/users/components/actions/index.js index 4e63a85df89..633bc4d8b15 100644 --- a/app/assets/javascripts/admin/users/components/actions/index.js +++ b/app/assets/javascripts/admin/users/components/actions/index.js @@ -9,6 +9,8 @@ import Reject from './reject.vue'; import Unban from './unban.vue'; import Unblock from './unblock.vue'; import Unlock from './unlock.vue'; +import Trust from './trust_user.vue'; +import Untrust from './untrust_user.vue'; export default { Activate, @@ -22,4 +24,6 @@ export default { Unblock, Unlock, Reject, + Trust, + Untrust, }; diff --git a/app/assets/javascripts/admin/users/components/actions/trust_user.vue b/app/assets/javascripts/admin/users/components/actions/trust_user.vue new file mode 100644 index 00000000000..41ff8d4120d --- /dev/null +++ b/app/assets/javascripts/admin/users/components/actions/trust_user.vue @@ -0,0 +1,62 @@ +<script> +import { GlDisclosureDropdownItem } from '@gitlab/ui'; +import { sprintf, s__, __ } from '~/locale'; +import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub'; +import { I18N_USER_ACTIONS } from '../../constants'; + +// TODO: To be replaced with <template> content in https://gitlab.com/gitlab-org/gitlab/-/issues/320922 +const messageHtml = ` + <p>${s__('AdminUsers|When not being monitored for spam:')}</p> + <ul> + <li>${s__( + 'AdminUsers|The user can create issues, notes, snippets, and merge requests that appear to be spam without being blocked.', + )}</li> + </ul> + <p>${s__('AdminUsers|You can untrust this user in the future.')}</p> +`; + +export default { + components: { + GlDisclosureDropdownItem, + }, + props: { + username: { + type: String, + required: true, + }, + path: { + type: String, + required: true, + }, + }, + methods: { + onClick() { + eventHub.$emit(EVENT_OPEN_CONFIRM_MODAL, { + path: this.path, + method: 'put', + modalAttributes: { + title: sprintf(s__('AdminUsers|Stop monitoring %{username} for possible spam?'), { + username: this.username, + }), + actionCancel: { + text: __('Cancel'), + }, + actionPrimary: { + text: I18N_USER_ACTIONS.trust, + attributes: { variant: 'confirm' }, + }, + messageHtml, + }, + }); + }, + }, +}; +</script> + +<template> + <gl-disclosure-dropdown-item @action="onClick"> + <template #list-item> + <slot></slot> + </template> + </gl-disclosure-dropdown-item> +</template> diff --git a/app/assets/javascripts/admin/users/components/actions/untrust_user.vue b/app/assets/javascripts/admin/users/components/actions/untrust_user.vue new file mode 100644 index 00000000000..da59833af07 --- /dev/null +++ b/app/assets/javascripts/admin/users/components/actions/untrust_user.vue @@ -0,0 +1,56 @@ +<script> +import { GlDisclosureDropdownItem } from '@gitlab/ui'; +import { sprintf, s__, __ } from '~/locale'; +import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub'; +import { I18N_USER_ACTIONS } from '../../constants'; + +// TODO: To be replaced with <template> content in https://gitlab.com/gitlab-org/gitlab/-/issues/320922 +const messageHtml = `<p>${s__( + 'AdminUsers|You can trust this user in the future if necessary.', +)}</p>`; + +export default { + components: { + GlDisclosureDropdownItem, + }, + props: { + username: { + type: String, + required: true, + }, + path: { + type: String, + required: true, + }, + }, + methods: { + onClick() { + eventHub.$emit(EVENT_OPEN_CONFIRM_MODAL, { + path: this.path, + method: 'put', + modalAttributes: { + title: sprintf(s__('AdminUsers|Re-enable spam monitoring for %{username}?'), { + username: this.username, + }), + actionCancel: { + text: __('Cancel'), + }, + actionPrimary: { + text: I18N_USER_ACTIONS.untrust, + attributes: { variant: 'confirm' }, + }, + messageHtml, + }, + }); + }, + }, +}; +</script> + +<template> + <gl-disclosure-dropdown-item @action="onClick"> + <template #list-item> + <slot></slot> + </template> + </gl-disclosure-dropdown-item> +</template> diff --git a/app/assets/javascripts/admin/users/constants.js b/app/assets/javascripts/admin/users/constants.js index 9cd61d6b1db..43c9a8749cd 100644 --- a/app/assets/javascripts/admin/users/constants.js +++ b/app/assets/javascripts/admin/users/constants.js @@ -19,4 +19,6 @@ export const I18N_USER_ACTIONS = { deleteWithContributions: s__('AdminUsers|Delete user and contributions'), ban: s__('AdminUsers|Ban user'), unban: s__('AdminUsers|Unban user'), + trust: s__('AdminUsers|Trust user'), + untrust: s__('AdminUsers|Untrust user'), }; diff --git a/app/assets/javascripts/ci/runner/components/runner_details.vue b/app/assets/javascripts/ci/runner/components/runner_details.vue index 0ec2ef30c20..477d28c6c28 100644 --- a/app/assets/javascripts/ci/runner/components/runner_details.vue +++ b/app/assets/javascripts/ci/runner/components/runner_details.vue @@ -120,12 +120,9 @@ export default { }} </p> <p class="gl-mb-0"> - <gl-link - :href="tokenExpirationHelpUrl" - target="_blank" - class="gl-reset-font-size" - >{{ __('Learn more') }}</gl-link - > + <gl-link :href="tokenExpirationHelpUrl" target="_blank">{{ + __('Learn more') + }}</gl-link> </p> </help-popover> </template> @@ -156,12 +153,9 @@ export default { " > <template #link="{ content }" - ><gl-link - :href="$options.RUNNER_MANAGERS_HELP_URL" - target="_blank" - class="gl-reset-font-size" - >{{ content }}</gl-link - ></template + ><gl-link :href="$options.RUNNER_MANAGERS_HELP_URL" target="_blank">{{ + content + }}</gl-link></template > </gl-sprintf> </help-popover> diff --git a/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_base.vue b/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_base.vue index e3d3360cd0c..3b9f14a218f 100644 --- a/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_base.vue +++ b/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_base.vue @@ -47,16 +47,20 @@ export default { <template> <li class="gl-mt-5 gl-pb-5 gl-border-b gl-relative"> - <time-ago-tooltip :time="event.created_at" class="gl-float-right gl-text-secondary" /> + <time-ago-tooltip + :time="event.created_at" + class="gl-float-right gl-font-sm gl-text-secondary gl-mt-2" + /> <gl-avatar-link :href="author.web_url"> <gl-avatar-labeled :label="author.name" :sub-label="authorUsername" + inline-labels :src="author.avatar_url" - :size="32" + :size="24" /> </gl-avatar-link> - <div class="gl-pl-8 gl-mt-2" data-testid="event-body"> + <div class="gl-pl-7" data-testid="event-body"> <div class="gl-text-secondary"> <gl-icon :class="iconClass" :name="iconName" /> <gl-sprintf v-if="message" :message="message"> diff --git a/app/assets/javascripts/issues/show/components/issue_header.vue b/app/assets/javascripts/issues/show/components/issue_header.vue index 211f3217ddc..c205a6361c7 100644 --- a/app/assets/javascripts/issues/show/components/issue_header.vue +++ b/app/assets/javascripts/issues/show/components/issue_header.vue @@ -115,11 +115,9 @@ export default { <template #status-badge> <gl-sprintf v-if="closedStatusLink" :message="statusText"> <template #link> - <gl-link - class="gl-reset-color! gl-reset-font-size gl-text-decoration-underline" - :href="closedStatusLink" - >{{ closedStatusText }}</gl-link - > + <gl-link class="gl-reset-color! gl-text-decoration-underline" :href="closedStatusLink">{{ + closedStatusText + }}</gl-link> </template> </gl-sprintf> <template v-else>{{ statusText }}</template> diff --git a/app/assets/javascripts/organizations/users/components/app.vue b/app/assets/javascripts/organizations/users/components/app.vue new file mode 100644 index 00000000000..ae22bedd69a --- /dev/null +++ b/app/assets/javascripts/organizations/users/components/app.vue @@ -0,0 +1,51 @@ +<script> +import { __, s__ } from '~/locale'; +import { createAlert } from '~/alert'; +import organizationUsersQuery from '../graphql/organization_users.query.graphql'; + +export default { + name: 'OrganizationsUsersApp', + i18n: { + users: __('Users'), + loadingPlaceholder: __('Loading'), + errorMessage: s__( + 'Organization|An error occurred loading the organization users. Please refresh the page to try again.', + ), + }, + inject: ['organizationGid'], + data() { + return { + users: [], + }; + }, + apollo: { + users: { + query: organizationUsersQuery, + variables() { + return { id: this.organizationGid }; + }, + update(data) { + return data.organization.organizationUsers.nodes; + }, + error(error) { + createAlert({ message: this.$options.i18n.errorMessage, error, captureError: true }); + }, + }, + }, + computed: { + loading() { + return this.$apollo.queries.users.loading; + }, + }, +}; +</script> + +<template> + <section> + <h1 class="gl-my-4 gl-font-size-h-display">{{ $options.i18n.users }}</h1> + <template v-if="loading"> + {{ $options.i18n.loadingPlaceholder }} + </template> + <div data-testid="organization-users">{{ users }}</div> + </section> +</template> diff --git a/app/assets/javascripts/organizations/users/graphql/organization_users.query.graphql b/app/assets/javascripts/organizations/users/graphql/organization_users.query.graphql new file mode 100644 index 00000000000..7b37186ba1a --- /dev/null +++ b/app/assets/javascripts/organizations/users/graphql/organization_users.query.graphql @@ -0,0 +1,14 @@ +query getOrganizationUsers($id: OrganizationsOrganizationID!) { + organization(id: $id) { + id + organizationUsers { + nodes { + badges + id + user { + id + } + } + } + } +} diff --git a/app/assets/javascripts/organizations/users/index.js b/app/assets/javascripts/organizations/users/index.js new file mode 100644 index 00000000000..76656243075 --- /dev/null +++ b/app/assets/javascripts/organizations/users/index.js @@ -0,0 +1,29 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import OrganizationsUsersApp from './components/app.vue'; + +export const initOrganizationsUsers = () => { + const el = document.getElementById('js-organizations-users'); + + if (!el) return false; + + const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), + }); + + const { organizationGid } = convertObjectPropsToCamelCase(el.dataset); + + return new Vue({ + el, + name: 'OrganizationsUsersRoot', + apolloProvider, + provide: { + organizationGid, + }, + render(createElement) { + return createElement(OrganizationsUsersApp); + }, + }); +}; diff --git a/app/assets/javascripts/pages/organizations/organizations/users/index.js b/app/assets/javascripts/pages/organizations/organizations/users/index.js new file mode 100644 index 00000000000..12d53207b22 --- /dev/null +++ b/app/assets/javascripts/pages/organizations/organizations/users/index.js @@ -0,0 +1,3 @@ +import { initOrganizationsUsers } from '~/organizations/users'; + +initOrganizationsUsers(); diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss index 8fe45d4bb9d..d6500529170 100644 --- a/app/assets/stylesheets/utilities.scss +++ b/app/assets/stylesheets/utilities.scss @@ -65,8 +65,6 @@ min-width: 0; } -// .gl-font-size-inherit will be moved to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1466 -.gl-font-size-inherit, .font-size-inherit { font-size: inherit; } .gl-w-16 { width: px-to-rem($grid-size * 2); } .gl-w-64 { width: px-to-rem($grid-size * 8); } diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 9634257209d..ee78d5a8c35 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -310,7 +310,7 @@ class Admin::UsersController < Admin::ApplicationController end def users_with_included_associations(users) - users.includes(:authorized_projects) # rubocop: disable CodeReuse/ActiveRecord + users.includes(:authorized_projects, :trusted_with_spam_attribute) # rubocop: disable CodeReuse/ActiveRecord end def admin_making_changes_for_another_user? diff --git a/app/helpers/admin/user_actions_helper.rb b/app/helpers/admin/user_actions_helper.rb index 969c5d5a0b5..ba40b3c8a8d 100644 --- a/app/helpers/admin/user_actions_helper.rb +++ b/app/helpers/admin/user_actions_helper.rb @@ -16,6 +16,7 @@ module Admin unlock_actions delete_actions ban_actions + trust_actions @actions end @@ -66,5 +67,19 @@ module Admin @actions << 'ban' end end + + def trust_actions + return if @user.internal? || + @user.blocked_pending_approval? || + @user.banned? || + @user.blocked? || + @user.deactivated? + + @actions << if @user.trusted? + 'untrust' + else + 'trust' + end + end end end diff --git a/app/helpers/organizations/organization_helper.rb b/app/helpers/organizations/organization_helper.rb index 48ba9d4ab84..312f55c11d2 100644 --- a/app/helpers/organizations/organization_helper.rb +++ b/app/helpers/organizations/organization_helper.rb @@ -42,6 +42,12 @@ module Organizations } end + def organization_user_app_data(organization) + { + organization_gid: organization.to_global_id + } + end + private def shared_groups_and_projects_app_data diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 1bdc0cbb453..75ff2da2322 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -262,7 +262,9 @@ module UsersHelper delete_with_contributions: admin_user_path(:id, hard_delete: true), admin_user: admin_user_path(:id), ban: ban_admin_user_path(:id), - unban: unban_admin_user_path(:id) + unban: unban_admin_user_path(:id), + trust: trust_admin_user_path(:id), + untrust: untrust_admin_user_path(:id) } end diff --git a/app/models/user.rb b/app/models/user.rb index fdc0b531521..bc256ef0f31 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -601,6 +601,12 @@ class User < MainClusterwide::ApplicationRecord scope :by_provider_and_extern_uid, ->(provider, extern_uid) { joins(:identities).merge(Identity.with_extern_uid(provider, extern_uid)) } scope :by_ids_or_usernames, -> (ids, usernames) { where(username: usernames).or(where(id: ids)) } scope :without_forbidden_states, -> { where.not(state: FORBIDDEN_SEARCH_STATES) } + scope :trusted, -> do + where('EXISTS (?)', ::UserCustomAttribute + .select(1) + .where('user_id = users.id') + .trusted_with_spam) + end strip_attributes! :name @@ -769,6 +775,8 @@ class User < MainClusterwide::ApplicationRecord external when 'deactivated' deactivated + when "trusted" + trusted else active_without_ghosts end diff --git a/app/views/admin/users/_users.html.haml b/app/views/admin/users/_users.html.haml index d4a9009a0cf..bbb068c3680 100644 --- a/app/views/admin/users/_users.html.haml +++ b/app/views/admin/users/_users.html.haml @@ -44,6 +44,9 @@ = gl_tab_link_to admin_users_path(filter: "wop"), { item_active: active_when(params[:filter] == 'wop'), class: 'gl-border-0!' } do = s_('AdminUsers|Without projects') = gl_tab_counter_badge(limited_counter_with_delimiter(User.without_projects)) + = gl_tab_link_to admin_users_path(filter: "trusted"), { item_active: active_when(params[:filter] == 'trusted'), class: 'gl-border-0!' } do + = s_('AdminUsers|Trusted') + = gl_tab_counter_badge(limited_counter_with_delimiter(User.trusted)) .nav-controls = render_if_exists 'admin/users/admin_email_users' = render_if_exists 'admin/users/admin_export_user_permissions' diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index 83f7d743755..a3be188854d 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -2,7 +2,7 @@ - if event.visible_to_user?(current_user) .event-item - .event-item-timestamp + .event-item-timestamp.gl-font-sm #{time_ago_with_tooltip(event.created_at)} - if event.wiki_page? diff --git a/app/views/organizations/organizations/users.html.haml b/app/views/organizations/organizations/users.html.haml index a01c5f5045e..5fb9d786e0b 100644 --- a/app/views/organizations/organizations/users.html.haml +++ b/app/views/organizations/organizations/users.html.haml @@ -1 +1,4 @@ - page_title _('Users') + +#js-organizations-users{ data: organization_user_app_data(@organization) } + |