123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- import React from 'react';
- import ErrorsModal from 'misago/components/threads/moderation/errors-list'; // jshint ignore:line
- import MergeThreads from 'misago/components/threads/moderation/merge'; // jshint ignore:line
- import MoveThreads from 'misago/components/threads/moderation/move'; // jshint ignore:line
- import * as select from 'misago/reducers/selection'; // jshint ignore:line
- import ajax from 'misago/services/ajax'; // jshint ignore:line
- import modal from 'misago/services/modal'; // jshint ignore:line
- import snackbar from 'misago/services/snackbar'; // jshint ignore:line
- import store from 'misago/services/store'; // jshint ignore:line
- import Countdown from 'misago/utils/countdown'; // jshint ignore:line
- export default class extends React.Component {
- /* jshint ignore:start */
- callApi = (ops, successMessage, onSuccess=null) => {
- // freeze threads
- this.props.threads.forEach((thread) => {
- this.props.freezeThread(thread.id);
- });
- // list ids
- const ids = this.props.threads.map((thread) => {
- return thread.id;
- });
- // always return current acl
- ops.push({op: 'add', path: 'acl', value: true});
- ajax.patch(this.props.api, { ids, ops }).then(
- (data) => {
- // unfreeze
- this.props.threads.forEach((thread) => {
- this.props.freezeThread(thread.id);
- });
- // update threads
- data.forEach((thread) => {
- this.props.updateThread(thread);
- });
- // show success message and call callback
- snackbar.success(successMessage);
- if (onSuccess) {
- onSuccess();
- }
- },
- (rejection) => {
- // unfreeze
- this.props.threads.forEach((thread) => {
- this.props.freezeThread(thread.id);
- });
- // escape on non-400 error
- if (rejection.status !== 400) {
- return snackbar.apiError(rejection);
- }
- // build errors list
- let errors = [];
- let threadsMap = {}
- this.props.threads.forEach((thread) => {
- threadsMap[thread.id] = thread;
- });
- rejection.forEach(({id, detail }) => {
- if (typeof threadsMap[id] !== 'undefined') {
- errors.push({
- errors: detail,
- thread: threadsMap[id]
- });
- }
- });
- modal.show(
- <ErrorsModal errors={errors} />
- );
- }
- );
- };
- pinGlobally = () => {
- this.callApi([
- {
- op: 'replace',
- path: 'weight',
- value: 2
- }
- ], gettext("Selected threads were pinned globally."));
- };
- pinLocally = () => {
- this.callApi([
- {
- op: 'replace',
- path: 'weight',
- value: 1
- }
- ], gettext("Selected threads were pinned locally."));
- };
- unpin = () => {
- this.callApi([
- {
- op: 'replace',
- path: 'weight',
- value: 0
- }
- ], gettext("Selected threads were unpinned."));
- };
- approve = () => {
- this.callApi([
- {
- op: 'replace',
- path: 'is-unapproved',
- value: false
- }
- ], gettext("Selected threads were approved."));
- };
- open = () => {
- this.callApi([
- {
- op: 'replace',
- path: 'is-closed',
- value: false
- }
- ], gettext("Selected threads were opened."));
- };
- close = () => {
- this.callApi([
- {
- op: 'replace',
- path: 'is-closed',
- value: true
- }
- ], gettext("Selected threads were closed."));
- };
- unhide = () => {
- this.callApi([
- {
- op: 'replace',
- path: 'is-hidden',
- value: false
- }
- ], gettext("Selected threads were unhidden."));
- };
- hide = () => {
- this.callApi([
- {
- op: 'replace',
- path: 'is-hidden',
- value: true
- }
- ], gettext("Selected threads were hidden."));
- };
- move = () => {
- modal.show(
- <MoveThreads
- callApi={this.callApi}
- categories={this.props.categories}
- categoriesMap={this.props.categoriesMap}
- route={this.props.route}
- user={this.props.user}
- />
- );
- };
- merge = () => {
- const errors = [];
- this.props.threads.forEach((thread) => {
- if (!thread.acl.can_merge) {
- errors.append({
- 'id': thread.id,
- 'title': thread.title,
- 'errors': [
- gettext("You don't have permission to merge this thread with others.")
- ]
- });
- }
- });
- if (this.props.threads.length < 2) {
- snackbar.info(
- gettext("You have to select at least two threads to merge."));
- } else if (errors.length) {
- modal.show(<ErrorsModal errors={errors} />);
- return;
- } else {
- modal.show(<MergeThreads {...this.props} />);
- }
- };
- delete = () => {
- if (!confirm(gettext("Are you sure you want to delete selected threads?"))) {
- return;
- }
- this.props.threads.map((thread) => {
- this.props.freezeThread(thread.id);
- });
- const ids = this.props.threads.map((thread) => { return thread.id; });
- ajax.delete(this.props.api, ids).then(() => {
- this.props.threads.map((thread) => {
- this.props.freezeThread(thread.id);
- this.props.deleteThread(thread);
- });
- snackbar.success(gettext("Selected threads were deleted."));
- }, (rejection) => {
- if (rejection.status === 400) {
- const failedThreads = rejection.map((thread) => { return thread.id; });
- this.props.threads.map((thread) => {
- this.props.freezeThread(thread.id);
- if (failedThreads.indexOf(thread.id) === -1) {
- this.props.deleteThread(thread);
- }
- });
- modal.show(<ErrorsModal errors={rejection} />);
- } else {
- snackbar.apiError(rejection);
- }
- });
- };
- /* jshint ignore:end */
- getPinGloballyButton() {
- if (!this.props.moderation.can_pin_globally) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- className="btn btn-link"
- onClick={this.pinGlobally}
- type="button"
- >
- <span className="material-icon">
- bookmark
- </span>
- {gettext("Pin threads globally")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- getPinLocallyButton() {
- if (!this.props.moderation.can_pin) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- className="btn btn-link"
- onClick={this.pinLocally}
- type="button"
- >
- <span className="material-icon">
- bookmark_border
- </span>
- {gettext("Pin threads locally")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- getUnpinButton() {
- if (!this.props.moderation.can_pin) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- className="btn btn-link"
- onClick={this.unpin}
- type="button"
- >
- <span className="material-icon">
- panorama_fish_eye
- </span>
- {gettext("Unpin threads")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- getMoveButton() {
- if (!this.props.moderation.can_move) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- className="btn btn-link"
- onClick={this.move}
- type="button"
- >
- <span className="material-icon">
- arrow_forward
- </span>
- {gettext("Move threads")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- getMergeButton() {
- if (!this.props.moderation.can_merge) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- className="btn btn-link"
- onClick={this.merge}
- type="button"
- >
- <span className="material-icon">
- call_merge
- </span>
- {gettext("Merge threads")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- getApproveButton() {
- if (!this.props.moderation.can_approve) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- className="btn btn-link"
- onClick={this.approve}
- type="button"
- >
- <span className="material-icon">
- done
- </span>
- {gettext("Approve threads")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- getOpenButton() {
- if (!this.props.moderation.can_close) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- className="btn btn-link"
- onClick={this.open}
- type="button"
- >
- <span className="material-icon">
- lock_open
- </span>
- {gettext("Open threads")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- getCloseButton() {
- if (!this.props.moderation.can_close) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- className="btn btn-link"
- onClick={this.close}
- type="button"
- >
- <span className="material-icon">
- lock_outline
- </span>
- {gettext("Close threads")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- getUnhideButton() {
- if (!this.props.moderation.can_unhide) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- className="btn btn-link"
- onClick={this.unhide}
- type="button"
- >
- <span className="material-icon">
- visibility
- </span>
- {gettext("Unhide threads")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- getHideButton() {
- if (!this.props.moderation.can_hide) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- onClick={this.hide}
- type="button"
- className="btn btn-link"
- >
- <span className="material-icon">
- visibility_off
- </span>
- {gettext("Hide threads")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- getDeleteButton() {
- if (!this.props.moderation.can_delete) return null;
- /* jshint ignore:start */
- return (
- <li>
- <button
- className="btn btn-link"
- onClick={this.delete}
- type="button"
- >
- <span className="material-icon">
- clear
- </span>
- {gettext("Delete threads")}
- </button>
- </li>
- );
- /* jshint ignore:end */
- }
- render() {
- /* jshint ignore:start */
- return <ul className={this.props.className}>
- {this.getPinGloballyButton()}
- {this.getPinLocallyButton()}
- {this.getUnpinButton()}
- {this.getMoveButton()}
- {this.getMergeButton()}
- {this.getApproveButton()}
- {this.getOpenButton()}
- {this.getCloseButton()}
- {this.getUnhideButton()}
- {this.getHideButton()}
- {this.getDeleteButton()}
- </ul>;
- /* jshint ignore:end */
- }
- }
|