diff --git a/app/controllers/api/v1/groups/accounts_controller.rb b/app/controllers/api/v1/groups/accounts_controller.rb index e09b21e2..61759000 100644 --- a/app/controllers/api/v1/groups/accounts_controller.rb +++ b/app/controllers/api/v1/groups/accounts_controller.rb @@ -26,7 +26,8 @@ class Api::V1::Groups::AccountsController < Api::BaseController def update authorize @group, :update_account? - GroupAccount.where(group: @group, account_id: current_account.id).update(group_account_params) + @account = @group.accounts.find(params[:account_id]) + GroupAccount.where(group: @group, account: @account).update(group_account_params) render_empty end diff --git a/app/javascript/gabsocial/actions/groups.js b/app/javascript/gabsocial/actions/groups.js index eac34371..01ac5503 100644 --- a/app/javascript/gabsocial/actions/groups.js +++ b/app/javascript/gabsocial/actions/groups.js @@ -51,6 +51,10 @@ export const GROUP_REMOVE_STATUS_REQUEST = 'GROUP_REMOVE_STATUS_REQUEST'; export const GROUP_REMOVE_STATUS_SUCCESS = 'GROUP_REMOVE_STATUS_SUCCESS'; export const GROUP_REMOVE_STATUS_FAIL = 'GROUP_REMOVE_STATUS_FAIL'; +export const GROUP_UPDATE_ROLE_REQUEST = 'GROUP_UPDATE_ROLE_REQUEST'; +export const GROUP_UPDATE_ROLE_SUCCESS = 'GROUP_UPDATE_ROLE_SUCCESS'; +export const GROUP_UPDATE_ROLE_FAIL = 'GROUP_UPDATE_ROLE_FAIL'; + export const fetchGroup = id => (dispatch, getState) => { if (!me) return; @@ -521,4 +525,43 @@ export function groupRemoveStatusFail(groupId, id, error) { id, error, }; +}; + +export function updateRole(groupId, id, role) { + return (dispatch, getState) => { + if (!me) return; + + dispatch(updateRoleRequest(groupId, id)); + + api(getState).patch(`/api/v1/groups/${groupId}/accounts?account_id=${id}`, { role }).then(response => { + dispatch(updateRoleSuccess(groupId, id)); + }).catch(error => { + dispatch(updateRoleFail(groupId, id, error)); + }); + }; +}; + +export function updateRoleRequest(groupId, id) { + return { + type: GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST, + groupId, + id, + }; +}; + +export function updateRoleSuccess(groupId, id) { + return { + type: GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS, + groupId, + id, + }; +}; + +export function updateRoleFail(groupId, id, error) { + return { + type: GROUP_REMOVED_ACCOUNTS_CREATE_FAIL, + groupId, + id, + error, + }; }; \ No newline at end of file diff --git a/app/javascript/gabsocial/features/groups/members/index.js b/app/javascript/gabsocial/features/groups/members/index.js index ed396d4f..31cdb738 100644 --- a/app/javascript/gabsocial/features/groups/members/index.js +++ b/app/javascript/gabsocial/features/groups/members/index.js @@ -8,14 +8,18 @@ import LoadingIndicator from '../../../components/loading_indicator'; import { fetchMembers, expandMembers, + updateRole, + createRemovedAccount, } from '../../../actions/groups'; import { FormattedMessage } from 'react-intl'; import AccountContainer from '../../../containers/account_container'; import Column from '../../ui/components/column'; import ScrollableList from '../../../components/scrollable_list'; +import DropdownMenuContainer from '../../../containers/dropdown_menu_container'; const mapStateToProps = (state, { params: { id } }) => ({ group: state.getIn(['groups', id]), + relationships: state.getIn(['group_relationships', id]), accountIds: state.getIn(['user_lists', 'groups', id, 'items']), hasMore: !!state.getIn(['user_lists', 'groups', id, 'next']), }); @@ -47,9 +51,9 @@ class GroupMembers extends ImmutablePureComponent { }, 300, { leading: true }); render () { - const { accountIds, hasMore, group } = this.props; - - if (!group || !accountIds) { + const { accountIds, hasMore, group, relationships, dispatch } = this.props; + + if (!group || !accountIds || !relationships) { return ( @@ -65,7 +69,23 @@ class GroupMembers extends ImmutablePureComponent { onLoadMore={this.handleLoadMore} emptyMessage={} > - {accountIds.map(id => )} + {accountIds.map(id => { + let menu = []; + + if (relationships.get('admin')) { + menu = [ + { text: 'Remove from group', action: () => dispatch(createRemovedAccount(group.get('id'), id)) }, + { text: 'Make administrator', action: () => dispatch(updateRole(group.get('id'), id, 'admin')) }, + ] + } + + return ( +
+ true} /> + {menu.length > 0 && } +
+ ); + })}
); diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss index 2ae7da3e..ab469abd 100644 --- a/app/javascript/styles/application.scss +++ b/app/javascript/styles/application.scss @@ -28,6 +28,7 @@ @import 'gabsocial/components/compose-form'; @import 'gabsocial/components/group-card'; @import 'gabsocial/components/group-detail'; +@import 'gabsocial/components/group-accounts'; @import 'gabsocial/components/group-form'; @import 'gabsocial/components/group-sidebar-panel'; diff --git a/app/javascript/styles/gabsocial/components/group-accounts.scss b/app/javascript/styles/gabsocial/components/group-accounts.scss new file mode 100644 index 00000000..c858b2e6 --- /dev/null +++ b/app/javascript/styles/gabsocial/components/group-accounts.scss @@ -0,0 +1,10 @@ +.group-account-wrapper { + position: relative; + + & > div > .icon-button { + position: absolute; + right: 5px; + top: 50%; + transform: translateY(-50%); + } +} \ No newline at end of file diff --git a/app/models/status.rb b/app/models/status.rb index 4a39eb50..9c055116 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -23,7 +23,7 @@ # in_reply_to_account_id :bigint(8) # poll_id :bigint(8) # group_id :integer -# quote_id :bigint(8) +# quote_of_id :bigint(8) # class Status < ApplicationRecord diff --git a/db/schema.rb b/db/schema.rb index b495de26..04b3db48 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -93,7 +93,7 @@ ActiveRecord::Schema.define(version: 2019_08_04_115634) do t.bigint "account_id" t.string "image_file_name" t.string "image_content_type" - t.integer "image_file_size" + t.bigint "image_file_size" t.datetime "image_updated_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -157,10 +157,10 @@ ActiveRecord::Schema.define(version: 2019_08_04_115634) do t.string "actor_type" t.boolean "discoverable" t.string "also_known_as", array: true - t.boolean "is_pro", default: false, null: false - t.datetime "pro_expires_at" t.datetime "silenced_at" t.datetime "suspended_at" + t.boolean "is_pro", default: false, null: false + t.datetime "pro_expires_at" t.boolean "is_verified", default: false, null: false t.boolean "is_donor", default: false, null: false t.boolean "is_investor", default: false, null: false @@ -658,8 +658,8 @@ ActiveRecord::Schema.define(version: 2019_08_04_115634) do create_table "status_pins", force: :cascade do |t| t.bigint "account_id", null: false t.bigint "status_id", null: false - t.datetime "created_at", default: -> { "CURRENT_TIMESTAMP" }, null: false - t.datetime "updated_at", default: -> { "CURRENT_TIMESTAMP" }, null: false + t.datetime "created_at", default: -> { "now()" }, null: false + t.datetime "updated_at", default: -> { "now()" }, null: false t.index ["account_id", "status_id"], name: "index_status_pins_on_account_id_and_status_id", unique: true end