MaazAli/phanime

View on GitHub
server/methods/revisions.js

Summary

Maintainability
F
1 wk
Test Coverage
Meteor.methods({
    revisionsAnimeAdd: function(anime) {

        // Ensure integerity of data
        check(anime, AnimeRevisionsSchema);

        // Get auto values
        anime.slug = getSlug(anime.canonicalTitle);
        anime.createdAt = new Date();

        // Ensure uniqueness
        var titleCheck = Anime.findOne({canonicalTitle: anime.canonicalTitle});
        var slugCheck = Anime.findOne({slug: anime.slug});

        var uniqueCondition;

        if (titleCheck || slugCheck) {
            uniqueCondition = false;
            throw new Meteor.Error(403, "The canonical title of the anime was found in our database");

        } else {
            uniqueCondition = true;
        }

        // We want the anime to be unique and the user to be logged in
        // before we add in the revision
        if (uniqueCondition && Meteor.user()) {

            var revisionAnime = {
                contentType: 'Anime',
                type: 'Addition',
                userId: Meteor.user()._id,
                username: Meteor.user().displayName(),
                content: anime
            };

            // Insert the document into the database
            Revisions.insert(revisionAnime, function(error, _id) {
                console.log(_id);
            });

        }


    },
    revisionsAnimeAddEdit: function(anime) {

        // The edited version of the anime is sent
        check(anime, AnimeRevisionsSchema);
        
        var oldAnime = Anime.findOne({_id: anime._id});
        var uniqueCondition;


        var changedAttributesAnime = {
            _id: anime._id
        };
        // Let's add anime entries that changed
        for (var key in anime) {
            if (anime.hasOwnProperty(key)) {
                if (key === "totalEpisodes") {
                    console.log(anime[key]);
                    console.log(oldAnime[key]);
                    console.log(!_.isEqual(anime[key], oldAnime[key]));
                }
                if (!_.isEqual(anime[key], oldAnime[key])) {
                    changedAttributesAnime[key] = anime[key];
                }
                // We'll delete this property from oldAnime if it has it
                if (oldAnime[key]) {
                    delete oldAnime[key]
                }
            }
        }

        // Just incase, we'll clean the oldAnime object, before we add the keys
        AnimeRevisionsSchema.clean(oldAnime, {autoConvert: false, removeEmptyStrings: false, trimStrings: false, getAutoValues: false});

        // console.log("After clean");
        // console.log(oldAnime);

        // Now we'll have all the key's that  are in oldAnime that were removed in 
        // anime, which are essentially attributes that have changed
        // so we'll add those as well, their values will be null.
        for(var key in oldAnime) {
            if (oldAnime.hasOwnProperty(key) && oldAnime[key]) {
                changedAttributesAnime[key] = null;
            }
        }

        // If we got slug set to null, we'll just remove it 
        // from the changed attributes
        if (changedAttributesAnime.slug === null) {
            delete changedAttributesAnime.slug;
        }

        console.log(changedAttributesAnime);

        // if the canonicalTitle of the anime was changed...
        if (changedAttributesAnime.canonicalTitle) {

            // Ensure uniqueness
            var titleCheck = Anime.findOne({canonicalTitle: changedAttributesAnime.canonicalTitle});

            // These checks are mainly done to give good errors to the user
            // Checks will be done against the database when the anime is actually 
            // being submitted
            if (titleCheck) {
                uniqueCondition = false;
                throw new Meteor.Error(403, "The canonical title of the anime was found in our database");
            } else {
                uniqueCondition = true;
            }

        } else {
            uniqueCondition = true;
        }

        // We also want to know if the coverImageChanged

        if (changedAttributesAnime.coverImage) {
            // First of all this means that now coverImage contains a URL
            // additionally we'll now use the new url format 
            changedAttributesAnime.newImageURLFormat = true;
        }

        if (_.isEmpty(changedAttributesAnime)) {
            throw new Meteor.Error(403, "Nothing was changed, revision not committed");
        } 

        // We want the anime to be unique and the user to be logged in
        // and ensure the we actually had some changed attributes
        // before we add in the revision
        if (uniqueCondition && Meteor.user() && !_.isEmpty(changedAttributesAnime)) {

            // console.log("Changed attributes after condition check: " + changedAttributesAnime);

            var revisionAnime = {
                contentType: 'Anime',
                type: 'Revision',
                userId: Meteor.user()._id,
                username: Meteor.user().displayName(),
                content: changedAttributesAnime
            };

            // Insert the document into the database
            Revisions.insert(revisionAnime, function(error, _id) {
                if (error) {
                    console.log(error);
                    // console.log("Errored!" + error.reason);
                    throw new Meteor.Error(403, error.reason);
                } else {
                    console.log("Revision created with id: " + _id);
                }
            });

        }


    },
    revisionsAnimeUpdate: function(anime) {

        // Ensure integerity of data
        check(anime, AnimeRevisionsSchema);

        // If revision is an Addition (updated), we need to check for uniqueness

        // if anime._id exists than this anime already is in the database
        // in which case this is a revision, else it's an addition (updated)
        // we do revision updates in another method
        if (!anime._id) {

            var titleCheck = Anime.findOne({canonicalTitle: anime.canonicalTitle});
            var slugCheck = Anime.findOne({slug: getSlug(anime.canonicalTitle)});
            var uniqueCondition;

            if (titleCheck || slugCheck) {
                uniqueCondition = false;
                throw new Meteor.Error(403, "The canonical title of the anime was found in our database");
            } else {
                uniqueCondition = true;
            }

            if (uniqueCondition && Meteor.user()) {

                Revisions.update({_id: anime.revisionId}, {$set: {content: anime}}, {filter: false}, function(error, num) {
                    if (error)
                        throw new Meteor.Error(403, error.reason);

                });

            }
        }


    },
    revisionAnimeUpdateEdit: function(anime) {

        // Checks don't work properly currently, since 
        // we are sending a subset of the anime document


        // currently, you can only update a revision if you're a moderator
        if (Meteor.user().isModerator()) {

            console.log(anime);
            Revisions.update({_id: anime.revisionId}, {$set: {content: anime}}, function(error, num) {
                if (error)
                    throw new Meteor.Error(403, error.reason);

            });            
        }

    },

    // Revision Approved 
    revisionApproved: function(revision) {

        // We should actually be pulling the revision from the database
        // to ensure the revision object itself hasn't been screwed up
        // during transmision. For now, we'll leave it be.

        // If the user isn't a moderator 
        // they cannot approve revisions
        if (!Meteor.user().isModerator())
            throw new Meteor.Error(403, "Only moderators are allowed to approve revisions");


        console.log(revision.content);

        // Anime Additions should work
        if (revision.contentType === 'Anime') {


            // We can basically insert 
            if (revision.type === 'Addition') {
                // revision.content contains the anime object

                // We'll just throw it in the createAnimeObject method to generate the default fields
                var animeObject = revision.content;

                // If coverImage exists we should add in the new url image format field
                if (animeObject.coverImage) {
                    animeObject.newImageURLFormat = true;
                }

                // Ensure uniqueness
                var titleCheck = Anime.findOne({canonicalTitle: animeObject.canonicalTitle});
                var slugCheck = Anime.findOne({slug: animeObject.slug});

                var uniqueCondition;

                if (titleCheck || slugCheck) {
                    uniqueCondition = false;
                } else {
                    uniqueCondition = true;
                }

                if (uniqueCondition) {

                    var animeId = Anime.insert(animeObject);

                    // We only want to initiate the image upload if 
                    // there was an image url provided
                    if (animeId && animeObject.coverImage) {
                        console.log('We\'re about to upload the image');
                        Meteor.call("uploadImageFromUrl", animeObject.coverImage, 'anime', 'cover', animeId, function(error, result) {
                            if (error) {
                                throw new Meteor.Error(403, error.reason);
                            }
                        });
                    }

                    // Update the user's positive scoring
                    Meteor.users.update({_id: revision.userId}, {$inc: {revisionApprovedCount: 1}});


                    // We also update the revision's status to Approved here
                    Revisions.update({_id: revision._id}, {$set: {status: "Approved", decisionByUsername: Meteor.user().originalUsername, decisionByUserId: Meteor.user()._id}});

                    // We'll also send an alert to the user
                    Alerts.insert({
                        event: "revisionApproved",
                        userId: revision.userId,
                        properties: {
                            decisionByUsername: Meteor.user().originalUsername,
                            decisionByUserId: Meteor.user()._id,
                            contentType: revision.contentType,
                            contentId: animeId,
                            revisionType: revision.type,
                            animeTitle: revision.content.canonicalTitle ? revision.content.canonicalTitle : null
                        },
                        createdAt: new Date(),
                        read: false
                    }, function(error, _id) {
                        if (error)
                            throw new Meteor.Error('403', error.reason);
                    });

                    return animeId;
                } else {
                    throw new Meteor.Error(403, 'Anime is not unique');
                }
            }

            // These are for edits of existing anime
            if (revision.type === 'Revision') {
                // let's check if we need to do a unique check
                // unique check is only necessary if the canonicalTitle exists
                var uniqueCondition;
                if (revision.content.canonicalTitle) {

                    var titleCheck = Anime.findOne({canonicalTitle: revision.content.canonicalTitle});

                    var uniqueCondition;

                    if (titleCheck) {
                        uniqueCondition = false;
                    } else {
                        uniqueCondition = true;
                    }
                
                } else {
                    uniqueCondition = true;
                }    

                // only do the update, if we find it's unique
                if (uniqueCondition) {

                    // if coverImage exists, then we should also 
                    // add that we'll be using the new url format for
                    // the image
                    if (revision.content.coverImage) {
                        revision.content.newImageURLFormat = true;
                    }

                    // Let's remove the revisionId/_id if they are in there 
                    if (revision.content.revisionId) 
                        delete revision.content.revisionId;

                    var contentId = revision.content._id;

                    if (revision.content._id)
                        delete revision.content._id;


                    // We want to unset properties that are "null"
                    // this could include the slug as well, however,
                    // that shouldn't be much of an issue considering 
                    // that it's an autovalue and it'll re-generate itself
                    var unsetProperties = {};
                    for(var key in revision.content) {
                        if (revision.content[key] === null) {
                            unsetProperties[key] = "";
                            delete revision.content[key];
                        }

                    }
                    // set properties
                    console.log("Set properties");
                    console.log(revision.content);

                    // unset properties
                    console.log("Unset properties");
                    console.log(unsetProperties);

                    // We update before, since uploadImageFromUrl will also be doing an anime update of it's own
                    if (_.isEmpty(unsetProperties)) {
                        Anime.update({_id: contentId}, {$set: revision.content});
                    } else {
                        Anime.update({_id: contentId}, {$unset: unsetProperties, $set: revision.content});
                    }


                    // Check if we have coverImage, if we do, we assume it's a url and then try to upload it
                    if (revision.content.coverImage && contentId) {

                        console.log('we\'re about to upload the image');
                        Meteor.call("uploadImageFromUrl", revision.content.coverImage, 'anime', 'cover', contentId, function(error, result) {
                            if (error) {
                                throw new Meteor.Error(403, error.reason);
                            }
                        });                    
                    }

                    // Update the user's positive scoring
                    Meteor.users.update({_id: revision.userId}, {$inc: {revisionApprovedCount: 1}});


                    // We also update the revision's status to Approved here
                    Revisions.update(
                        {
                            _id: revision._id
                        }, 
                        {
                            $set: {
                                status: "Approved", 
                                updatedAt: new Date(), 
                                decisionByUsername: Meteor.user().originalUsername, 
                                decisionByUserId: Meteor.user()._id
                            }
                        }
                    );

                    // We'll also send an alert to the user
                    Alerts.insert({
                        event: "revisionApproved",
                        userId: revision.userId,
                        properties: {
                            decisionByUsername: Meteor.user().originalUsername,
                            decisionByUserId: Meteor.user()._id,
                            contentType: revision.contentType,
                            contentId: contentId,
                            revisionType: revision.type,
                            animeTitle: revision.content.canonicalTitle ? revision.content.canonicalTitle : null
                        },
                        createdAt: new Date(),
                        read: false
                    }, function(error, _id) {
                        if (error)
                            throw new Meteor.Error('403', error.reason);
                    });


                } else {
                    throw new Meteor.Error(403, 'Anime is not unique');
                }
            }
        }
    
    },

    revisionDeclined: function(revision) {
        // Increase the declined revision count first
        Meteor.users.update({_id: revision.userId}, {$inc: {revisionDeclinedCount: 1}});

        // Update the revision's status to declined
        Revisions.update({_id: revision._id}, {$set: {status: "Declined", updatedAt: new Date(), decisionByUsername: Meteor.user().originalUsername, decisionByUserId: Meteor.user()._id}});

        // We'll also send an alert to the user
        Alerts.insert({
            event: "revisionDeclined",
            userId: revision.userId,
            properties: {
                decisionByUsername: Meteor.user().originalUsername,
                decisionByUserId: Meteor.user()._id,
                contentType: revision.contentType,
                contentId: revision.content._id,
                revisionType: revision.type,
                animeTitle: revision.content.canonicalTitle ? revision.content.canonicalTitle : null
            },
            createdAt: new Date(),
            read: false
        }, function(error, _id) {
            if (error)
                throw new Meteor.Error('403', error.reason);
        });

    },

    revisionReopen: function(revision) {
        // Increase the declined revision count first

        // if the revision was declined before, we should remove a point from declined count, since we're re-opening it.
        if (revision.status === 'Declined') {
            Meteor.users.update({_id: revision.userId}, {$inc: {revisionDeclinedCount: -1}});
        } else if (revision.status === 'Approved') {
            // You can't Open an Approved revision, however, if that functionality is ever added 
            // this will remove 1 from approved count
            Meteor.users.update({_id: revision.userId}, {$inc: {revisionApprovedCount: -1}});
        }

        // Update the revision's status to Open
        Revisions.update({_id: revision._id}, {$set: {status: "Open", updatedAt: new Date(), decisionByUsername: Meteor.user().originalUsername, decisionByUserId: Meteor.user()._id}});

        // We'll also send an alert to the user
        Alerts.insert({
            event: "revisionReopened",
            userId: revision.userId,
            properties: {
                decisionByUsername: Meteor.user().originalUsername,
                decisionByUserId: Meteor.user()._id,
                contentType: revision.contentType,
                contentId: revision.content._id,
                revisionType: revision.type,
                animeTitle: revision.content.canonicalTitle ? revision.content.canonicalTitle : null
            },
            createdAt: new Date(),
            read: false
        }, function(error, _id) {
            if (error)
                throw new Meteor.Error('403', error.reason);
        });

    }
});