I am currently working on a role called "read_incident" which should allow EES Users read the incidents of their assignment group.
Therefor I did the following:
created a role "read_incident"
assigned the role to group "Service Desk"
created a user "Denis" and added him to the "Service Desk" group
modified the query incident Business rule using an addorcondition to include my "read_incident" role to read incidents. (now you either have the "itil role", or the "read_incident" role to read incidents.
created an ACL with dynamic filter to read incidents if the assignment group is one of my groups.
Now I created a homepage using a gauge of a list report of incidents which are assigned to "service desk" group.
As admin I can see all the incidents of course. But when I impersonate "Denis", the incident list reports the following "No records to display"
So nothing is blocking me from reading incidents, but somehow there is no Data match.
I tried creating a new incident and assign it to the "service desk" but still this incident isn't visible for the user "Denis".
What I know until now:
- Business rule is 100% working, because no "data is blocked" - I can query the incident table
The Business rule:
if (!gs.hasRole("itil").addOrCondition(!gs.hasRole("read_incident") && gs.isInteractive()) {
var u = gs.getUserID();
var qc = current.addQuery("caller_id", u).addOrCondition("opened_by", u).addOrCondition("watch_list", "CONTAINS", u);
gs.print("query restricted to user: " + u);
}
Your business rule is not correct: gs.hasRole() method returns true or false, you cannot use the method addOrCondition() there. There is also an error in your if sentence, it is needed another ")" at the end of the condition.
Try the following:
Business Rule Condition
(!gs.hasRole("itil") || !gs.hasRole("read_incident")) && gs.isInteractive()
Script
(function executeRule(current, previous /*null when async*/) {
var u = gs.getUserID();
current.addQuery("caller_id", u).addOrCondition("opened_by", u).addOrCondition("watch_list", "CONTAINS", u);
})(current, previous);
It is better to use the Condition field when possible, it improves the performance. I'm not sure if the business rule script meets your needs, I think you should check if the user is member of the current assignment_group, right?
Related
As mentioned in the comments below, if only students can turn something in, then I would need to be able to grade and return the assignment even though it had not been turned in yet. To clarify, the assignment was made with the API and I have control over the class and the student.
As mentioned in additional comments below, even if you do not return the assignment, the student will still see the assigned grade, which fulfills the goal of this question. Thus, turn-ins and returns are not needed to grade assignments with the Classroom API.
There are a couple of questions similar to this one, but not as complete and none seem to have concrete answers, so I will try and be as specific as possible. I need to be able to force-turn-in a student's assignment, even though they have not done so yet, and then put a grade, and then return it. With the script below, I am getting two errors.
One, "Invalid JSON payload received. Unknown name "assignment_submission": Cannot find field. (line 15, file "GRADES CLASSROOM")" even though this is in the Classroom reference (https://developers.google.com/classroom/reference/rest/v1/courses.courseWork.studentSubmissions).
Two, when I try and use the "return" method, (second last line of code) it returns the error "Missing name after . operator. (line 17, file "GRADES CLASSROOM")" when I try and save the code, forcing me to comment it out before saving. I think many people have been looking for an answer to how to set this process up.
function returnGrade () {
var submit ={assignedGrade: 80};
var upDate = {updateMask: 'assignedGrade'};
var resource1 = {
assignmentSubmission: {
addAttachments: [{
link:{
url: "URL"
},
}],
},
};
// Classroom.Courses.CourseWork.StudentSubmissions.turnIn(resource1, COURSE ID, WORK ID, "EMAIL");
Classroom.Courses.CourseWork.StudentSubmissions.patch(submit, COURSE ID, WORK ID, "EMAIL", upDate);
// Classroom.Courses.CourseWork.StudentSubmissions.return(resource1, COURSE ID, WORK ID, "EMAIL");
}
In the comments below, the code to set the grade has been resolved. We only need to see how to return the grade.
Short answer
Course work submissions (assignments, questions) could only be done by students or by using their credentials. We could uso OAuth for this but if you don't want to use OAuth, then turn in the course work by using the student account, in other words, make a function to be ran by with the student account and make another function to do the the patch / return operations with the teacher / domain administrator account.
It's possible to grade student course work submissions even if they aren't submitted by using patch.
Course work submissions can only be returned to students if they were turned if first
Code
The following code added the grades to one student "successfully". At this time I was able to verify that drafGrade was correctly registered on the web UI.
function doPatch(){
var courseId = '6915813348';
var courseWorkId = '11297534926';
var studentSubmissions = Classroom.Courses.CourseWork.StudentSubmissions.list(courseId, courseWorkId,{'userId':'someone#gmail.com'});
var id = studentSubmissions['studentSubmissions'][0].id;
var studentSubmission = {
'assignedGrade': 99,
'draftGrade': 80
}
Classroom.Courses.CourseWork.StudentSubmissions.patch(
studentSubmission,
courseId,
courseWorkId,
id,
{
'updateMask':'assignedGrade,draftGrade'
}
);
}
The assignedGrade is visible to the teacher and student on the student work view
The draftGrade is visible to the teacher on the submissions view
Notes
I made some research and tests and found some "interesting things"
The error message
"Missing name after . operator. (line 17, file "GRADES CLASSROOM")"
Looks to be caused by the use of return in
Classroom.Courses.CourseWork.StudentSubmissions.return(resource1, COURSE ID, WORK ID, "EMAIL");
Reference: Google App Script
The error occurs because return is a JavaScript keyword. The alternative syntax is
Classroom.Courses.CourseWork.StudentSubmissions["return"](resource1, COURSE ID, WORK ID, "EMAIL")
But this requires that the related student submitted the course work otherwise the Classroom API will throw a Failed Precondition error.
I don't have a complete answer yet, but it's important to bear in mind that some tasks depend on the user class role that could be teacher or student but not both for the same course.
So in order to make an assignment submission the corresponding method should be called someway on behalf the corresponding student and in order to return an assignment this should be called someway on behalf a class teacher.
References
From Method: courses.courseWork.studentSubmissions.turnIn
This may only be called by the student that owns the specified student submission.
From Method: courses.courseWork.studentSubmiss.return
Only a teacher of the course that contains the requested student submission may call this method.
I'm having two tables subscription and subscription_event. A subscription_event can be one of the following types:
public enum SubscriptionEventType {
CREATED,
CANCELED,
CHARGED_SUCCESSFULLY,
CHARGED_UNSUCCESSFULLY,
EXPIRED,
TRIAL_STARTED,
TRIAL_ENDED,
WENT_ACTIVE, // Subscription went active and can be charged from now on.
WENT_PAST_DUE;
public Long getValue() {
return this.ordinal() + 1L;
}
}
What I want to do is to keep the state of subscription to the most recent event. The problem: Those events do not come in correct order. E.g. it is possible to get a CHARGED_SUCCESSFULLY event before a WENT_ACTIVE event.
So there are several way how I can accomplish what I need. First of all I can check the condition in my application layer and always set that "most recent" state based on the timestamp of the event.
Long subscriptionId = lastRecordedEvent.getSubscriptionId();
if(event.getTimestamp() > lastRecordedEvent.getTimestamp()) {
// Since the current event is more recent than all other events
// we also have to update the subscription state
subscriptionRepository.updateState(subscriptionId, event.getTimestamp());
}
However, I do not want to do this in my application layer. Another solution would be to use a TRIGGER on the subscription_event table and let that on decide whether to update the relevant subscription or not. The reason why I do not go for that just yet is because I know that triggers can be easily forgotten and also be a pain to maintain. Also I know one should take every other option into account before using a TRIGGER but since I am not a SQL/MySQL expert I'm not aware of all my options here.
So what would be the most practicable way to keep subscription up-to-date in this situation?
Insert your event as usual into the table and then execute the following
UPDATE subscriptions set state=events.state
FROM subscriptions inner join events on subscriptions.id = events.subscriptionID
Where events.SubscriptionId = ? and events.Timestamp =
(select max(timestamp) from events where events.SubscriptionId = ?)
You will need to pass parameters for the two ?s to be the subscription id of the event you just inserted
EDIT
An alternative approach is rather than have a status field in the database, create a view for your subscriptions and always query the view instead.
CREATE VIEW vw_subscriptions as
Select s.id, otherfields from subscription, coalesce(e.Status, 1) as status
from subscriptions s left outer join events e on s.id=e.subscriptionId
AND e.timestamp =
(select max(timestamp) from events where subscriptionId=s.id)
If you are worried about forgetting/maintaining the SQL or triggers, document them as comments in your repository functions and maintain all changes to the database as a change script that you store with your source code. That way your changes are all in your source control.
I send over proper json formatted code, according to v2 api docs:
lists/subscribe.json
"GROUPINGS":[{"id":removed_id,"name":"grouping_name","groups":["group_name"]}]
I get back information about a member... It does not say they are interested in that group name..
lists/member-info.json
"GROUPINGS":[{"id":removed_id,"name":"grouping_name","form_field":"hidden","groups":
[{"name":"group_name","interested":false},{"name":"other_group_name","interested":false},
{"name":"other_group_name2","interested":false},{"name":"other_group_name3","interested":false}]}]
I do not understand how I can get these users to show up as "subscribed" to a group within my grouping. I have been trying for nearly 5 hours now. I have tried:
making sure the groups: value is an [] array.
trying out making that value a string (which surprisingly did not throw errors)
capitalizing "GROUPINGS" when sending it in merge_vars
not capitalizing "groupings" when sending in merge_vars
using the lists/update-member.json method to update these groups
using the name of my interest group instead of grouping in the grouping array.
using the option replace_interests on both true and false
In conclusion,
I had to email mailchimp a support ticket. Without changing my code at all - it works this morning. Interestingly enough, mailchimp was experiencing many issues yesterday with servers being down and alleged email hackings.
To be clear about which version of my code worked - following the API exactly for v2.
It was an error on mailchimp's end.
{
"id":"MY LIST ID",
"email":{
"email":"THE EMAIL TO SUBSCRIBE"
},
"merge_vars":{
"GROUPINGS":[
{
"id":THE GROUPING ID,
"groups":[
"THE NAME OF MY GROUP"
]
}
]
},
"double_optin":false,
"replace_interests":true,
"apikey":"MY API KEY"
}
Also, in case you are curious, replace_interests is true when the groups you send are supposed to replace existing groups the subscriber is interested in. False indicates that the groups you pass should be added to the interest groups.
If you are updating a member (method: lists/update-member), it may be best to set replace_interests to false just to make sure it does not overwrite your existing interest groups (possibly with blank groups). The default value for it is true, so this could be another place prone to error.
Okay, so I built a database that allows me to keep track of calls being made to potential customers. Basically, the user generates a call list, and after calling each customer, they update the Call Status field in one of my tables to either "Person Reached", "Line Busy", "Disconnected Number", etc.
The problem I am having is that when I run the "Generate Call List" query (which I use to populate the Call List table), I am getting people who have already been reached. I have a condition that excludes anyone with a Call Status of "Person Reached", but for some reason it's not working. Here's the SQL.
SELECT [Telephone Status].Patient_ID, Max([Telephone Status].Date_Called)
AS [Date Last Called]
FROM [Telephone Status]
WHERE ((([Telephone Status].Call_Status_Details)="Call Back Later") AND
(([Telephone Status].Call_Status)<>"Person Reached"))
GROUP BY [Telephone Status].Patient_ID;
I thought that by using the Max function with the Date_Called field, that I would be excluding individuals who have a "Person Reached" status from the most recent call (Max), but I am still getting people who have been reached.
How can I check for this condition ("Person Reached") for the most recent Date_Called entry for each participant, and exclude them if the condition is True (Person was reached)?
The problem I am having is that when I run the "Generate Call List" query (which I use to populate the Call List table), I am getting people who have already been reached.
And how do you know that statement to be true? I think you need to examine the data in the [Telephone Status] table ... the Date_Called, Call_Status_Details, and Call_Status fields for one of the Patient_ID which was erroneously included on the call list.
I have a condition that excludes anyone with a Call Status of "Person Reached", but for some reason it's not working.
Not exactly ...
SELECT
ts.Patient_ID,
Max(ts.Date_Called) AS [Date Last Called]
FROM [Telephone Status] AS ts
WHERE
ts.Call_Status_Details = "Call Back Later"
AND ts.Call_Status <> "Person Reached"
GROUP BY ts.Patient_ID;
... so you have two criteria which both must be True.
Some ways a "person reached" could be included in the call list query are:
Call_Status_Details = "Call Back Later" but Call_Status is anything
other than "Person Reached", such as "Person R eached"; Person
Reachd"; etc.
A record with Call_Status_Details = "Call Back Later", a more recent
Date_Called than the last Call_Status = "Person Reached", but
some other valid value for Call_Status.
Indexes for those fields are corrupt.
The first is a data quality issue. You need to verify the data is consistently stored as you and your query expect.
I don't know about the second possibility. It depends on your business rules and how they are implemented.
The last possibility, index corruption, appears to be rare in my experience, but I've heard it can happen. Compact & Repair could fix it. See Tony Towes' Corrupt Microsoft Access MDBs FAQ for more detailed information.
Edit: You have a "Generate Call List" query which populates a Call List table. That is a situation where the Call List table could get out of sync with the latest updates to the [Telephone Status] table. It would be better to use the query itself for the call list rather than duplicating (possibly outdated) information in a separate table.
I am wondering how can I do the following about MS CRM 4.0:
I want to know for a campaign if a contact from a specific marketing list has not replied yet.
The field custom in the campaign response form is a partyfield. CRM doesn’t allow a PartyList field to be queried using a QueryExpression
Any ideas?
Thanks,
Katya
You cannot retrieve activityparty records directly, but you can use them in LinkEntities:
private bool contactHasResponded(Guid idCampaign, Guid idContact)
{
QueryExpression qryCampaignResponses = new QueryExpression("campaignresponse");
qryCampaignResponses.ColumnSet = new AllColumns();
qryCampaignResponses.Criteria = new FilterExpression();
qryCampaignResponses.Criteria.AddCondition("regardingobjectid", ConditionOperator.Equal, idCampaign);
LinkEntity leContact = new LinkEntity("campaignresponse", "activityparty", "activityid", "activityid", JoinOperator.Inner);
leContact.LinkCriteria = new FilterExpression();
leContact.LinkCriteria.AddCondition("partyid", ConditionOperator.Equal, idContact);
qryCampaignResponses.LinkEntities.Add(leContact);
List<gcCampaignresponse> lstCampaignResponses = gcCampaignresponse.RetrieveMultiple(m_svcCrm, qryCampaignResponses);
return (lstCampaignResponses.Count > 0);
}
This will tell you whether there's a campaign response for a given campaign and contact. (I use entity classes generated by Stunnware Tools, so the RetrieveMultiple call looks a little different, but I think you get my point).
If you turn this QueryExpression/LinkEntity construct upside down, you can also get all contacts that have responded to a given campaign (you can also restrict that to contacts in a certain marketing list through a second LinkEntity).
The only thing that's not possible directly with a single query is the "negative" check you are looking for, so you'll have to take this result and do an "outer join" against your marketing list to get the contacts that have not responded.