Commit dbed16cc authored by Florent Chehab's avatar Florent Chehab

New pendingModeration setup in frontend.

Fixes #55
parent 9ea5c94b
Pipeline #36195 failed with stages
in 4 minutes and 58 seconds
......@@ -5,6 +5,7 @@ from .pendingModeration import (
PendingModeration,
PendingModerationSerializer,
PendingModerationViewSet,
PendingModerationObjViewset,
)
from .forTestingModeration import (
ForTestingModeration,
......
......@@ -6,7 +6,7 @@ from django.db import models
from backend_app.custom import MySerializerWithJSON
from backend_app.fields import JSONField
from backend_app.utils import get_model_config, get_viewset_permissions
from rest_framework import serializers, viewsets
from rest_framework import serializers, viewsets, mixins
class PendingModeration(models.Model):
......@@ -56,3 +56,19 @@ class PendingModerationViewSet(viewsets.ModelViewSet):
permission_classes = get_viewset_permissions("PendingModerationViewSet")
queryset = PendingModeration.objects.all() # pylint: disable=E1101
serializer_class = PendingModerationSerializer
class PendingModerationObjViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
Viewset to retrieve the pending moderation data for an object
"""
permission_classes = get_viewset_permissions("PendingModerationObjViewset")
serializer_class = PendingModerationSerializer
def get_queryset(self):
content_type_id = self.kwargs["content_type_id"]
object_pk = self.kwargs["object_pk"]
return PendingModeration.objects.filter(
content_type=content_type_id, object_id=object_pk
)
import React from "react";
import CustomComponentForAPI from "../../../common/CustomComponentForAPI";
import { openFullScreenDialog, closeFullScreenDialog } from "../../../../redux/actions/fullScreenDialog";
import PropTypes from "prop-types";
......@@ -22,7 +23,6 @@ import Loading from "../../../common/Loading";
import dateTimeStrToStr from "../../../../utils/dateTimeStrToStr";
import editorStyle from "../../editors/common/editorStyle";
import CustomComponentForAPI from "../../../common/CustomComponentForAPI";
import getActions from "../../../../redux/api/getActions";
......@@ -32,7 +32,7 @@ import getActions from "../../../../redux/api/getActions";
* Component to display the previous versions of module
*
* @class History
* @extends {Component}
* @extends {CustomComponentForAPI}
*/
class History extends CustomComponentForAPI {
// Store the version that is being viewed
......@@ -217,10 +217,6 @@ class History extends CustomComponentForAPI {
* @memberof History
*/
render() {
if (!this.allApiDataIsReady()) {
return <></>;
}
return <></>;
}
}
......
......@@ -54,7 +54,7 @@ class ModuleWrapper extends Component {
* @memberof ModuleWrapper
*/
openEditorPanel(ignorePendingModeration = false) {
if (ignorePendingModeration || this.props.rawModelData.pending_moderation.length == 0) {
if (ignorePendingModeration || !this.props.rawModelData.has_pending_moderation) {
this.setState({ editorOpen: true });
} else {
this.alertThereIsSomethingPendingModeration();
......@@ -246,6 +246,7 @@ class ModuleWrapper extends Component {
{this.state.pendingModerationOpen ?
<PendingModeration
renderer={this}
modelInfo={{ contentTypeId: rawModelData.content_type_id, id: rawModelData.id }}
closePendingModerationPanel={() => this.closePendingModerationPanel()}
editFromPendingModeration={(pendingModelData) => this.editFromPendingModeration(pendingModelData)}
moderatePendingModeration={(modelData) => this.moderatePendingModeration(modelData)}
......
import React, { Component } from "react";
import React from "react";
import CustomComponentForAPI from "../../../common/CustomComponentForAPI";
import { connect } from "react-redux";
import { openFullScreenDialog, closeFullScreenDialog } from "../../../../redux/actions/fullScreenDialog";
......@@ -13,35 +14,37 @@ import IconButton from "@material-ui/core/IconButton";
import Typography from "@material-ui/core/Typography";
import CloseIcon from "@material-ui/icons/Close";
import Divider from "@material-ui/core/Divider";
import getActions from "../../../../redux/api/getActions";
import editorStyle from "../../editors/common/editorStyle";
import Loading from "../../../common/Loading";
const styles = theme => ({
...editorStyle(theme),
editButton: {
display: "block",
marginLeft: "auto",
marginRight: "auto",
marginTop: 2 * theme.spacing.unit,
marginBottom: 2 * theme.spacing.unit
}
});
/**
* Class to handle models that are pending moderation.
*
* @class PendingModeration
* @extends {Component}
* @extends {CustomComponentForAPI}
*/
class PendingModeration extends Component {
class PendingModeration extends CustomComponentForAPI {
constructor(props) {
super(props);
const { contentTypeId, id } = props.modelInfo;
// set the __apiAttr here so that we can read the correct data
this.__apiParam = {
pendingModeration: { contentTypeId, id }
};
}
/**
* Force update to force call of componentDidUpdate en mount and force the rendering of the moderation panel.
*
* @memberof PendingModeration
*/
componentDidMount(){
componentDidMount() {
super.componentDidMount();
this.forceUpdate();
}
......@@ -50,8 +53,9 @@ class PendingModeration extends Component {
*
* @memberof PendingModeration
*/
componentDidUpdate() {
this.props.openFullScreenDialog(this.renderPendingModerationPanel());
componentDidUpdate(prevProps, prevState, snapshot) {
super.componentDidUpdate(prevProps, prevState, snapshot);
this.props.openFullScreenDialog(this.renderPanel());
}
/**
......@@ -61,11 +65,11 @@ class PendingModeration extends Component {
* @memberof PendingModeration
*/
getRawModelDataFromPending() {
const { renderer } = this.props;
let pendingRawModelData = Object.assign({}, renderer.props.rawModelData.pending_moderation[0].new_object);
// we have to copy the original ID
pendingRawModelData.id = renderer.props.rawModelData.id;
return pendingRawModelData;
const pendingObject = this.getLatestReadData("pendingModeration")[0];
return Object.assign(
{},
pendingObject.new_object,
{ id: pendingObject.object_id });
}
/**
......@@ -112,6 +116,7 @@ class PendingModeration extends Component {
closePanel() {
this.props.closeFullScreenDialog();
this.props.closePendingModerationPanel();
this.props.resetPendingModeration();
}
/**
......@@ -120,7 +125,11 @@ class PendingModeration extends Component {
* @returns
* @memberof PendingModeration
*/
renderPendingModerationPanel() {
renderPanel() {
if (!this.allApiDataIsReady()) {
return <Loading />;
}
const { classes } = this.props,
pendingModelData = this.getRawModelDataFromPending();
......@@ -146,6 +155,12 @@ class PendingModeration extends Component {
);
}
/**
* @override
*
* @returns
* @memberof PendingModeration
*/
render() {
return <></>;
}
......@@ -153,6 +168,7 @@ class PendingModeration extends Component {
PendingModeration.propTypes = {
classes: PropTypes.object.isRequired,
modelInfo: PropTypes.object.isRequired,
editFromPendingModeration: PropTypes.func.isRequired,
closePendingModerationPanel: PropTypes.func.isRequired,
moderatePendingModeration: PropTypes.func.isRequired,
......@@ -167,15 +183,38 @@ PendingModeration.defaultProps = {
closePendingModerationPanel: () => console.error("Dev forgot something...")
};
const mapStateToProps = (state) => {
return {
pendingModeration: state.api.pendingModerationObjSpecific
};
};
const mapDispatchToProps = (dispatch) => {
return {
api: {
pendingModeration: (param) => dispatch(getActions("pendingModerationObj").readSpecific(`${param.contentTypeId}/${param.id}`)),
},
resetPendingModeration: () => dispatch(getActions("pendingModerationObj").setInvalidatedSpecific(true)),
openFullScreenDialog: (innerNodes) => dispatch(openFullScreenDialog(innerNodes)),
closeFullScreenDialog: () => dispatch(closeFullScreenDialog()),
};
};
const styles = theme => ({
...editorStyle(theme),
editButton: {
display: "block",
marginLeft: "auto",
marginRight: "auto",
marginTop: 2 * theme.spacing.unit,
marginBottom: 2 * theme.spacing.unit
}
});
export default compose(
withStyles(styles, { withTheme: true }),
connect(() => Object(), mapDispatchToProps)
connect(mapStateToProps, mapDispatchToProps)
)(PendingModeration);
export default function getModerationTooltipAndClass(nbPendingModeration, readOnly) {
export default function getModerationTooltipAndClass(hasPendingModeration, readOnly) {
if (readOnly) {
return {
moderTooltip: "Ce contenu n'est pas concerné par la modération.",
......@@ -6,20 +6,15 @@ export default function getModerationTooltipAndClass(nbPendingModeration, readOn
};
}
if (nbPendingModeration == 0) {
return {
moderTooltip: "Aucune mise-à-jour de ce module est en attente de modération pour ce module.",
moderClass: "green"
};
} else if (nbPendingModeration == 1) {
if (hasPendingModeration) {
return {
moderTooltip: "Une mise-à-jour de ce modèle est en attente de modération.",
moderClass: "orange"
};
} else {
return {
moderTooltip: "Plusieurs mises à jour de ce modèle sont en attente.",
moderClass: "orange"
moderTooltip: "Aucune mise-à-jour de ce module est en attente de modération pour ce module.",
moderClass: "green"
};
}
}
\ No newline at end of file
}
......@@ -19,16 +19,11 @@ import Tooltip from "@material-ui/core/Tooltip";
export default function renderFirstRow(userCanModerate) {
const { classes, theme, rawModelData } = this.props,
nbVersions = Math.max(0, rawModelData.nb_versions),
{ pending_moderation } = rawModelData;
let nbPendingModeration = 0;
if (pending_moderation) {
nbPendingModeration = pending_moderation.length;
}
hasPendingModeration = rawModelData.has_pending_moderation;
const readOnly = rawModelData.model_config.read_only,
{ versionTooltip, versionClass } = getVersionTooltipAndClass(nbVersions),
{ moderTooltip, moderClass } = getModerationTooltipAndClass(nbPendingModeration, readOnly),
{ moderTooltip, moderClass } = getModerationTooltipAndClass(hasPendingModeration, readOnly),
{ editTooltip, editClass } = getEditTooltipAndClass(readOnly, userCanModerate);
return (
......@@ -41,7 +36,7 @@ export default function renderFirstRow(userCanModerate) {
<Tooltip title={moderTooltip} placement="top">
<div style={{ display: "inline-block" }}> {/* Needed to fire events for the tooltip when below is disabled! when below is disabled!! */}
<MyBadge badgeContent={nbPendingModeration} color="secondary" minNumber={1}>
<MyBadge badgeContent={hasPendingModeration ? 1 : 0} color="secondary" minNumber={1}>
<IconButton aria-label="Modération" disabled={moderClass == "disabled" || moderClass == "green"} onClick={() => this.openPendingModerationPanel()} className={classes.button}>
<VerifiedUserIcon className={classes[moderClass]} />
</IconButton>
......
......@@ -36,6 +36,8 @@
# - IsOwner : (or )
#
# If you have a custom get_queryset function in your viewset, you need to specify an api_name
#####################################################
## Custom Viewsets that doesn't have a model behind
......@@ -252,6 +254,14 @@
viewset_permission: IsStaffOrReadOnly
ignore_in_admin: true
- viewset: PendingModerationObjViewset
import_location: abstract.my_model
api_end_point: pendingModerationObj
api_attr: (?P<content_type_id>[0-9]+)/(?P<object_pk>[0-9A-Za-z]+)
api_name: pendingModerationObj
read_only: true
ignore_in_admin: true
- model: ForTestingModeration
viewset: ForTestingModerationViewSet
import_location: abstract.my_model
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment