Kendo UI Scheduler: Delete/Edit/Update only specified events

8.2k Views Asked by At

Im working with the Kendo Scheduler and users can create, delete, update, edit events to my local database. But I'm working with different users on this webapp so I only want those users to be able to edit, delete and update events that they personally created. So user 1 can delete events created by user 1 but can't delete events created by user 2 or 3 etc...

I thought I just modify the model/controller to check the userID of the logged in user against the userID in the db of the event.

public virtual JsonResult Meetings_Destroy([DataSourceRequest] DataSourceRequest request, MeetingViewModel meeting)
{
    var userid = System.Convert.ToInt32(Session["userID"]);

    if (ModelState.IsValid)
        {
            if (meeting.UserID== userid)
            {
                meetingService.Delete(meeting, ModelState);
            }
            else
            {
                "cant delete"
            }
        }

    return Json(new[] { meeting });
}

But this doesn't seem to work, when click on delete the event dissapears but after reloading you see that it actually isn't really deleted from the db ... That of course isn't a good solution cause the goal is of course that that user just can't delete that event.

Any idea's?


VIEW

$(function () {
    $("#scheduler").kendoScheduler({
        date: new Date(Date.now()),
        startTime: new Date(2013, 5, 13, 9, 0, 0, 0),
        height: 800,
        timezone: "Etc/UTC",
        dataSource: {
            transport: {
                read: {
                    url: "@Url.Action("Meetings_Read", "Home")",
                    dataType: "json",
                    contentType: "application/json; charset=utf-8",
                    type: "POST"
                },
                update: {
                    url: "@Url.Action("Meetings_Update", "Home")",
                    dataType: "json",
                    contentType: "application/json; charset=utf-8",
                    type: "POST"
                },
                create: {
                    url: "@Url.Action("Meetings_Create", "Home")",
                    dataType: "json",
                    contentType: "application/json; charset=utf-8",
                    type: "POST"
                },
                destroy: {
                    url: "@Url.Action("Meetings_Destroy", "Home")",
                    dataType: "json",
                    contentType: "application/json; charset=utf-8",
                    type: "POST"
                },
                parameterMap: function (options, operation) {
                    if (operation === "read") {
                        var scheduler = $("#scheduler").data("kendoScheduler");
                        var result = {
                            start: scheduler.view().startDate(),
                            end: scheduler.view().endDate()
                        }
                        return kendo.stringify(result);
                    }
                    return kendo.stringify(options);
                }
            },
            error: error_handler,
                schema: {
                    model: {
                        id: "MeetingID",
                        fields: {
                            MeetingID: { type: "number" },
                            title: { from: "Title", type: "string", defaultValue: "No title", validation: { required: true } },
                            description: { from: "Description", type: "string" },
                            start: { from: "Start", type: "date" },
                            startTimezone: { from: "StartTimezone", type: "string" },
                            end: { from: "End", type: "date" },
                            endTimezone: { from: "EndTimezone", type: "string" },
                            recurrenceRule: { from: "RecurrenceRule", type: "string" },
                            recurrenceId: { from: "RecurrenceID", type: "number", defaultValue: null },
                            recurrenceException: { from: "RecurrenceException", type: "string" },
                            isAllDay: { from: "IsAllDay", type: "boolean" },
                            Timezone: { type: "string" },
                            RoomID: { type: "number", defaultValue: null },
                            Attendees: { type: "object" }
                        }
                    }
                }

            },

        });
    });

JAVASCRIPT

<script type="text/javascript">
    function error_handler(e) {
        if (e.errors) {
            var scheduler = $("#scheduler").data("kendoScheduler");
            scheduler.one("dataBinding", function (e) {
                e.preventDefault();
                for (var error in e.errors) {
                    alert("can't delete")
                }
            })
            var message = "Errors:\n";
            $.each(e.errors, function (key, value) {
                if ('errors' in value) {
                    $.each(value.errors, function () {
                        message += this + "\n";
                    });
                }
            });
            alert(message);
        }
    }

CONTROLLER

   public virtual JsonResult Meetings_Destroy([DataSourceRequest] DataSourceRequest request, MeetingViewModel meeting)
    {
            if (ModelState.IsValid)
            {
                if(meeting.UserID == System.Convert.ToInt32(Session["userID"]))
                {
                meetingService.Delete(meeting, ModelState);
                }
                else
                {
                ModelState.AddModelError("","cant delete");
                }
            }

        return Json(new[] { meeting });
    }
4

There are 4 best solutions below

0
On

It depends on how you are creating the meeting too.

Because to remove a task you just need a unique ID.

Right now it's just being deleted in JSON but not in the backend database, as I guess that meeting.id is not matching to the taskID generated when create event was fired.

I recommend to save taskID in ViewBag, SQL Table or somewhere, when task is created in the scheduler. Then pass this id as the parameter in your Meetings_Destroy method, when remove event is fired.

And [as mentioned in previous answer] use JavaScript remove event to validate logged in user, as e.preventDefault() can be used to restrict Meetings_Destroy method being fired if condition is not met. If debug is reached at Controller Method [Meetings_Destroy] it would remove event from scheduler [Either successfully removed in database or not], i-e from front end, but would bring it back on page refresh.

0
On

I have a same situation. I took a different approach to resolve it. In the edit function I compare task id and current userId and than I simply hide those button save, cancel and delete. These button will so only a user who created that.

function(e) 
{
    var customHide13= $(".k-scheduler-update, .k-scheduler-delete, .k-scheduler-cancel");

    if (taskId == userId)
        customHide13.show();
    else
        customHide13.hide();
},
5
On

ModelState.AddModelError("cant delete"); return Json(ModelState.ToDataSourceResult());

in the view

.Read("Grouping_Horizontal_Read", "Scheduler")
        .Create("Grouping_Horizontal_Create", "Scheduler")
        .Destroy("Grouping_Horizontal_Destroy", "Scheduler")
        .Update("Grouping_Horizontal_Update", "Scheduler")
        .Events(events => events.Error("error"))

.Events(events => events.Error("error")) is the trick and now importent the funktion for the error

function error(args) {
    if (args.errors) {

        var scheduler = $("#scheduler").data("kendoScheduler");
        scheduler.one("dataBinding", function (e) {
            e.preventDefault();   // cancel scheduler rebind if error occurs

            for (var error in args.errors) {

                alert(error + " args: " + args.errors[error].errors[0])

            }
        });
        args.sender.cancelChanges();
    }
}
1
On

I have a similar situation with my project where I have users that have limited access to do things on the calendar. I have found that you have to prevent things like Adds, Edits, and Deletes, that a user should not do, you can do this with the JavaScript events. Then, in the JavaScript functions, if a condiation is met (or not), then call the e.preventDefault(); method. Here's the demo on Client Events.

View (HTML 5 snippet)

remove: RemoveMe,
edit: EditMe,
add: AddMe,

View (MVC version snippet)

.Events(events =>
{
    events.Add("AddMe").Edit("EditMe").Remove("RemoveMe");
})

JavaScript

function AddMe (e) {
    if (SomeValue != SomeOtherValue) 
       e.preventDefault();
};

function EditMe (e) {
    if (SomeValue != SomeOtherValue) 
       e.preventDefault();
};

function RemoveMe (e) {
    if (SomeValue != SomeOtherValue) 
       e.preventDefault();
};

So, the good news is that this prevents the Calendar from showing updates (whether a Delete occurs or not), but it doesn't prevent the Delete Prompt (aka. "Are you sure you want to delete this event?"). Preventing the actions on the Client side is the way to go and you could extend it with alerts or notifications to the screen (since you would have the condition in the JavaScript function anyways), all to inform the user they can't do something.