mirror of
https://github.com/wassname/talk.git
synced 2026-07-01 18:40:35 +08:00
Merge pull request #134 from coralproject/close-comments
Close comments
This commit is contained in:
@@ -28,6 +28,7 @@ class Configure extends React.Component {
|
||||
// InfoBox has two settings. Enable or not and the content of it if it is enable.
|
||||
this.updateInfoBoxEnable = this.updateInfoBoxEnable.bind(this);
|
||||
this.updateInfoBoxContent = this.updateInfoBoxContent.bind(this);
|
||||
this.updateClosedMessage = this.updateClosedMessage.bind(this);
|
||||
|
||||
this.saveSettings = this.saveSettings.bind(this);
|
||||
}
|
||||
@@ -51,6 +52,11 @@ class Configure extends React.Component {
|
||||
this.props.dispatch(updateSettings({infoBoxContent}));
|
||||
}
|
||||
|
||||
updateClosedMessage (event) {
|
||||
const closedMessage = event.target.value;
|
||||
this.props.dispatch(updateSettings({closedMessage}));
|
||||
}
|
||||
|
||||
saveSettings () {
|
||||
this.props.dispatch(saveSettingsToServer());
|
||||
}
|
||||
@@ -78,6 +84,16 @@ class Configure extends React.Component {
|
||||
</p>
|
||||
</ListItemContent>
|
||||
</ListItem>
|
||||
<ListItem className={styles.configSettingInfoBox}>
|
||||
<ListItemContent>
|
||||
{lang.t('configure.closed-comments-desc')}
|
||||
<Textfield
|
||||
onChange={this.updateClosedMessage}
|
||||
value={this.props.settings.closedMessage}
|
||||
label={lang.t('configure.closed-comments-label')}
|
||||
rows={3}/>
|
||||
</ListItemContent>
|
||||
</ListItem>
|
||||
<ListItem className={`${styles.configSettingInfoBox} ${this.props.settings.infoBoxEnable ? null : styles.hidden}`} >
|
||||
<ListItemContent>
|
||||
<Textfield
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
"copy-and-paste": "Copy and paste code below into your CMS to embed your comment box in your articles",
|
||||
"moderate": "Moderate",
|
||||
"configure": "Configure",
|
||||
"community": "Community"
|
||||
"community": "Community",
|
||||
"closed-comments-desc": "Write a message for closed threads",
|
||||
"closed-comments-label": "Write a message..."
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
@@ -75,7 +77,9 @@
|
||||
"copy-and-paste": "Copiar y pegar el código de más abajo en tu CMS para colocar la caja de comentarios en tus articulos",
|
||||
"moderate": "Moderar",
|
||||
"configure": "Configurar",
|
||||
"community": "Comunidad"
|
||||
"community": "Comunidad",
|
||||
"closed-comments-desc": "Escribe un mensaje para cuando los comentarios se encuentran cerrados",
|
||||
"closed-comments-label": "Escribe un mensaje..."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ class CommentStream extends Component {
|
||||
const rootItem = this.props.items.assets && this.props.items.assets[rootItemId];
|
||||
const {actions, users, comments} = this.props.items;
|
||||
const {loggedIn, user, showSignInDialog, signInOffset} = this.props.auth;
|
||||
const {status} = this.props.config;
|
||||
const {status, closedMessage} = this.props.config;
|
||||
const {activeTab} = this.state;
|
||||
const expandForLogin = showSignInDialog ? {
|
||||
minHeight: document.body.scrollHeight + 150
|
||||
@@ -133,7 +133,7 @@ class CommentStream extends Component {
|
||||
author={user}
|
||||
/>
|
||||
</div>
|
||||
: <p>Comments are closed for this thread.</p>
|
||||
: <p>{closedMessage}</p>
|
||||
}
|
||||
{!loggedIn && <SignInContainer offset={signInOffset} />}
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ import coralApi from '../helpers/response';
|
||||
* Action name constants
|
||||
*/
|
||||
|
||||
export const UPDATE_SETTINGS = 'UPDATE_SETTINGS';
|
||||
export const OPEN_COMMENTS = 'OPEN_COMMENTS';
|
||||
export const CLOSE_COMMENTS = 'CLOSE_COMMENTS';
|
||||
export const ADD_ITEM = 'ADD_ITEM';
|
||||
|
||||
@@ -5,7 +5,8 @@ import * as actions from '../actions/config';
|
||||
|
||||
const initialState = Map({
|
||||
features: Map({}),
|
||||
status: 'open'
|
||||
status: 'open',
|
||||
closedMessage: ''
|
||||
});
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
|
||||
@@ -29,6 +29,14 @@ const AssetSchema = new Schema({
|
||||
type: Schema.Types.Mixed,
|
||||
default: null
|
||||
},
|
||||
closedAt: {
|
||||
type: Date,
|
||||
default: null
|
||||
},
|
||||
closedMessage: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
title: String,
|
||||
description: String,
|
||||
image: String,
|
||||
@@ -56,6 +64,13 @@ AssetSchema.index({
|
||||
background: true
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns true if the asset is closed, false else.
|
||||
*/
|
||||
AssetSchema.virtual('isClosed').get(function() {
|
||||
return this.closedAt && this.closedAt.getTime() <= new Date().getTime();
|
||||
});
|
||||
|
||||
/**
|
||||
* Finds an asset by its id.
|
||||
* @param {String} id identifier of the asset (uuid).
|
||||
|
||||
@@ -28,6 +28,16 @@ const SettingSchema = new Schema({
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
closedTimeout: {
|
||||
type: Number,
|
||||
|
||||
// Two weeks default expiry.
|
||||
default: 60 * 60 * 24 * 7 * 2
|
||||
},
|
||||
closedMessage: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
wordlist: [String]
|
||||
}, {
|
||||
timestamps: {
|
||||
|
||||
@@ -80,7 +80,20 @@ router.post('/', wordlist.filter('body'), (req, res, next) => {
|
||||
status = Promise.resolve('rejected');
|
||||
} else {
|
||||
status = Asset
|
||||
.rectifySettings(Asset.findById(asset_id))
|
||||
.rectifySettings(Asset.findById(asset_id).then((asset) => {
|
||||
if (!asset) {
|
||||
return Promise.reject(new Error('asset referenced is not found'));
|
||||
}
|
||||
|
||||
// Check to see if the asset has closed commenting...
|
||||
if (asset.isClosed) {
|
||||
|
||||
// They have, ensure that we send back an error.
|
||||
return Promise.reject(new Error(`asset has commenting closed because: ${asset.closedMessage}`));
|
||||
}
|
||||
|
||||
return asset;
|
||||
}))
|
||||
|
||||
// Return `premod` if pre-moderation is enabled and an empty "new" status
|
||||
// in the event that it is not in pre-moderation mode.
|
||||
|
||||
@@ -19,6 +19,7 @@ const settings = {id: '1', moderation: 'pre'};
|
||||
|
||||
describe('/api/v1/comments', () => {
|
||||
|
||||
// Ensure that the settings are always available.
|
||||
beforeEach(() => Promise.all([
|
||||
wordlist.insert(['bad words']),
|
||||
Setting.init(settings)
|
||||
@@ -143,11 +144,19 @@ describe('/api/v1/comments', () => {
|
||||
|
||||
describe('#post', () => {
|
||||
|
||||
let asset_id;
|
||||
|
||||
beforeEach(() => Asset.findOrCreateByUrl('https://coralproject.net/section/article-is-the-best').then((asset) => {
|
||||
|
||||
// Update the asset id.
|
||||
asset_id = asset.id;
|
||||
}));
|
||||
|
||||
it('should create a comment', () => {
|
||||
return chai.request(app)
|
||||
.post('/api/v1/comments')
|
||||
.set(passport.inject({roles: []}))
|
||||
.send({'body': 'Something body.', 'author_id': '123', 'asset_id': '1', 'parent_id': ''})
|
||||
.send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset_id, 'parent_id': ''})
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(201);
|
||||
expect(res.body).to.have.property('id');
|
||||
@@ -158,7 +167,7 @@ describe('/api/v1/comments', () => {
|
||||
return chai.request(app)
|
||||
.post('/api/v1/comments')
|
||||
.set(passport.inject({roles: []}))
|
||||
.send({'body': 'bad words are the baddest', 'author_id': '123', 'asset_id': '1', 'parent_id': ''})
|
||||
.send({'body': 'bad words are the baddest', 'author_id': '123', 'asset_id': asset_id, 'parent_id': ''})
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(201);
|
||||
expect(res.body).to.have.property('id');
|
||||
@@ -187,6 +196,43 @@ describe('/api/v1/comments', () => {
|
||||
expect(res.body).to.have.property('status', 'premod');
|
||||
});
|
||||
});
|
||||
|
||||
it('shouldn\'t create a comment when the asset has expired commenting', () => {
|
||||
return Asset.create({
|
||||
closedAt: new Date().setDate(0),
|
||||
closedMessage: 'tests said expired!'
|
||||
})
|
||||
.then((asset) => {
|
||||
return chai.request(app)
|
||||
.post('/api/v1/comments')
|
||||
.set(passport.inject({roles: []}))
|
||||
.send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset.id, 'parent_id': ''});
|
||||
})
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(500);
|
||||
})
|
||||
.catch((err) => {
|
||||
expect(err.response.body).to.not.be.null;
|
||||
expect(err.response.body).to.have.property('message');
|
||||
expect(err.response.body.message).to.contain('tests said expired!');
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a comment when the asset has not expired yet', () => {
|
||||
return Asset.create({
|
||||
closedAt: new Date().setDate(32),
|
||||
closedMessage: 'tests said expired!'
|
||||
})
|
||||
.then((asset) => {
|
||||
return chai.request(app)
|
||||
.post('/api/v1/comments')
|
||||
.set(passport.inject({roles: []}))
|
||||
.send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset.id, 'parent_id': ''});
|
||||
})
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(201);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user