we try to implement the nice local notifications extension of distriqt.
With the deactivate event new notifications were set:
notification.id = int(Math.random()*100);
notification.tickerText = _asde + " asdasd!";
notification.title = _asde + " asd!";
notification.body = "asd!";
notification.iconType = NotificationIconType.APPLICATION;
notification.count = 0;
notification.repeatInterval = 0;
notification.vibrate = false;
notification.playSound = true;
notification.soundName = "assets/sounds/notification.mp3";
notification.delay = secondsToDeath;
notification.data = "Some notification data to attach "+notification.id;
try
{
Notifications.service.notify( notification.id, notification );
_count ++;
Notifications.service.setBadgeNumber( _count );
}
catch (e:Error)
{
}
If the user clicks on the app and deactivates it again, new notifications were set.
The old notifications are still available and are displayed but we want the old to be deleted.
We haven't found a method to unregister the old notifications.
Any idea?
private static const DEACTIVATE_NOTIFICATION_ID_4 : int = 4;
Is declared.
if(_GoodA == true){
setSpielenFertigDate.time = 2400000*(1-_aktuellerFreudeWert/_maximalerFreudeWert);
var secondsToSpielenFertig:int = int((setSpielenFertigDate.time)/ 1000);
trace("halloe" + _fernseherAn.toString());
notification4.id = DEACTIVATE_NOTIFICATION_ID_4;
notification4.tickerText = "He test it!";
notification4.title = "sdf is happy!";
notification4.body = "sdf test is on!";
notification4.iconType = NotificationIconType.APPLICATION;
notification4.count = 0;
notification4.repeatInterval = 0;
notification4.vibrate = false;
notification4.playSound = true;
notification4.soundName = "assets/sounds/notification.mp3";
notification4.delay = secondsToSpielenFertig;
notification4.data = "Some notification data to attach "+ notification4.id;
try
{
Notifications.service.notify( notification4.id, notification4 );
_count ++;
Notifications.service.setBadgeNumber( _count );
}
catch (e:Error)
{
}
}
else{
trace("halloe2" + _fernseherAn.toString());
setSpielenDate.time = 5100000*(_aktuellerFreudeWert/_maximalerFreudeWert);
var secondsToSpielen:int = int((setSpielenDate.time)/ 1000);
notification4.id = DEACTIVATE_NOTIFICATION_ID_4;
notification4.tickerText = "He tested it!";
notification4.title = "sdf is unhappy!";
notification4.body = "sdf test is off!";
notification4.iconType = NotificationIconType.APPLICATION;
notification4.count = 0;
notification4.repeatInterval = 0;
notification4.vibrate = false;
notification4.playSound = true;
notification4.soundName = "assets/sounds/notification.mp3";
//Sekunden bis Nachricht geschickt wird
notification4.delay = secondsToSpielen;
notification4.data = "Some notification data to attach "+notification4.id;
try
{
Notifications.service.notify( notification4.id, notification4 );
_count ++;
Notifications.service.setBadgeNumber( _count );
}
catch (e:Error)
{
}
}
If the deactivate event of the app is fired it traces the correct part of the if and else clause. But it won't update the body and title...
There are two ways to do this with our extension. Both involve tracking the ID of the notification.
The first is to track your last notification and "cancel" it from the notification area. To do this you need to store at least the ID of the last created notification. The part of the code that you're probably interested in is the cancel function, this removes a notification from the notification panel by specifying the id of the notification to remove.
Somewhere in your class declare a reference to the last notification:
private var _lastNotification : Notification;
Then in your deactivate handler:
var notification:Notification = new Notification();
notification.id = int(Math.random()*100);
notification.tickerText = "Deactivated";
notification.title = "TEST";
notification.body = "Application Deactivated";
if (_lastNotification != null)
Notifications.service.cancel( _lastNotification.id );
Notifications.service.notify( notification.id, notification );
// Set this to be the recent notification displayed
_lastNotification = notification;
The second option is to use a single notification id for all of your deactivate notifications. In this case you choose a constant ID to use for your notification and update the notification as required. The notification manager will not show an additional notification but simply update the one with the specified ID (or show it if it has been closed by the user).
private static const DEACTIVATE_NOTIFICATION_ID : int = 10;
var notification:Notification = new Notification();
notification.id = DEACTIVATE_NOTIFICATION_ID;
notification.tickerText = "Deactivated";
notification.title = "TEST";
notification.body = "Application Deactivated";
Notifications.service.notify( notification.id, notification );
Hope this helps!
Related
Is it possible to migrate users using the MS Graph API in Azure AD?
If so, please explain how to migrate users from one tenant to the other using the MS Graph API.
You can export the users with MS Graph. Note, you can't export the passwords. This means that you have to create a new password and share it with the users. Or choose a random password and let the users reset their password using the self-service password rest feature.
Here is an example how to export the users from a directly
public static async Task ListUsers(GraphServiceClient graphClient)
{
Console.WriteLine("Getting list of users...");
DateTime startTime = DateTime.Now;
Dictionary<string, string> usersCollection = new Dictionary<string, string>();
int page = 0;
try
{
// Get all users
var users = await graphClient.Users
.Request()
.Select(e => new
{
e.DisplayName,
e.Id
}).OrderBy("DisplayName")
.GetAsync();
// Iterate over all the users in the directory
var pageIterator = PageIterator<User>
.CreatePageIterator(
graphClient,
users,
// Callback executed for each user in the collection
(user) =>
{
usersCollection.Add(user.DisplayName, user.Id);
return true;
},
// Used to configure subsequent page requests
(req) =>
{
var d = DateTime.Now - startTime;
Console.WriteLine($"{string.Format(TIME_FORMAT, d.Days, d.Hours, d.Minutes, d.Seconds)} users: {usersCollection.Count}");
// Set a variable to the Documents path.
string filePrefix = "0";
if (usersCollection.Count >= 1000000)
{
filePrefix = usersCollection.Count.ToString()[0].ToString();
}
page++;
if (page >= 50)
{
page = 0;
string docPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), $"users_{filePrefix}.json");
System.IO.File.WriteAllTextAsync(docPath, JsonSerializer.Serialize(usersCollection));
}
Thread.Sleep(200);
return req;
}
);
await pageIterator.IterateAsync();
// Write last page
string docPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), $"users_all.json");
System.IO.File.WriteAllTextAsync(docPath, JsonSerializer.Serialize(usersCollection));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
After you export the users, you can import them back to the other tenant. The following example creates test users. Change the code to set the values from the files you exported earlier. Also, this code uses batch with 20 users in single operation.
public static async Task CreateTestUsers(GraphServiceClient graphClient, AppSettings appSettings, bool addMissingUsers)
{
Console.Write("Enter the from value: ");
int from = int.Parse(Console.ReadLine()!);
Console.Write("Enter the to value: ");
int to = int.Parse(Console.ReadLine()!);
int count = 0;
Console.WriteLine("Starting create test users operation...");
DateTime startTime = DateTime.Now;
Dictionary<string, string> existingUsers = new Dictionary<string, string>();
// Add the missing users
if (addMissingUsers)
{
// Set a variable to the Documents path.
string docPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "users.json");
if (!System.IO.File.Exists(docPath))
{
Console.WriteLine("Can't find the '{docPath}' file.");
}
string usersFile = System.IO.File.ReadAllText(docPath);
existingUsers = JsonSerializer.Deserialize<Dictionary<string, string>>(usersFile);
if (existingUsers == null)
{
Console.WriteLine("Can't deserialize users");
return;
}
Console.WriteLine($"There are {existingUsers.Count} in the directory");
}
List<User> users = new List<User>();
// The batch object
var batchRequestContent = new BatchRequestContent();
for (int i = from; i < to; i++)
{
// 1,000,000
string ID = TEST_USER_PREFIX + i.ToString().PadLeft(7, '0');
if (addMissingUsers)
{
if (existingUsers.ContainsKey(ID))
continue;
}
count++;
try
{
var user = new User
{
DisplayName = ID,
JobTitle = ID.Substring(ID.Length - 1),
Identities = new List<ObjectIdentity>()
{
new ObjectIdentity
{
SignInType = "userName",
Issuer = appSettings.TenantName,
IssuerAssignedId = ID
},
new ObjectIdentity
{
SignInType = "emailAddress",
Issuer = appSettings.TenantName,
IssuerAssignedId = $"{ID}#{TEST_USER_SUFFIX}"
}
},
PasswordProfile = new PasswordProfile
{
Password = "1",
ForceChangePasswordNextSignIn = false
},
PasswordPolicies = "DisablePasswordExpiration,DisableStrongPassword"
};
users.Add(user);
if (addMissingUsers)
{
Console.WriteLine($"Adding missing {ID} user");
}
// POST requests are handled a bit differently
// The SDK request builders generate GET requests, so
// you must get the HttpRequestMessage and convert to a POST
var jsonEvent = graphClient.HttpProvider.Serializer.SerializeAsJsonContent(user);
HttpRequestMessage addUserRequest = graphClient.Users.Request().GetHttpRequestMessage();
addUserRequest.Method = HttpMethod.Post;
addUserRequest.Content = jsonEvent;
if (batchRequestContent.BatchRequestSteps.Count >= BATCH_SIZE)
{
var d = DateTime.Now - startTime;
Console.WriteLine($"{string.Format(TIME_FORMAT, d.Days, d.Hours, d.Minutes, d.Seconds)}, count: {count}, user: {ID}");
// Run sent the batch requests
var returnedResponse = await graphClient.Batch.Request().PostAsync(batchRequestContent);
// Dispose the HTTP request and empty the batch collection
foreach (var step in batchRequestContent.BatchRequestSteps) ((BatchRequestStep)step.Value).Request.Dispose();
batchRequestContent = new BatchRequestContent();
}
// Add the event to the batch operations
batchRequestContent.AddBatchRequestStep(addUserRequest);
// Console.WriteLine($"User '{user.DisplayName}' successfully created.");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
I have a Template created in DS which contains custom tags which are mapped to Salesforce fields. The template works well when used via the JS button example code provided by DS and the fields appear as expected.
I am now trying to automate the process using the Docusign SOAPAPI. When creating the envelope the custom fields aren't populated; even the signer fields.
Below is my code:-
DocusignAPI.ArrayOfRecipient1 recipients = new DocusignAPI.ArrayOfRecipient1();
recipients.Recipient = new list<DocusignAPI.Recipient>();
DocusignAPI.Recipient recipient = new DocusignAPI.Recipient();
recipient.Email = signer_email;
recipient.UserName = signer_name;
recipient.ID = 1;
recipient.Type_x = 'Signer';
recipient.RoutingOrder = 1;
recipients.Recipient.add(recipient);
DocusignAPI.ArrayOfTemplateReference templateReferences = new DocusignAPI.ArrayOfTemplateReference();
templateReferences.TemplateReference = new list<DocusignAPI.TemplateReference>();
DocusignAPI.TemplateReference templateReference = new DocusignAPI.TemplateReference();
TemplateReference.Template = '6bc2930f-6d46-4804-a9fc-69d1cf3ebe09';
templateReference.TemplateLocation = 'Server';
templateReferences.TemplateReference.add(templateReference);
DocusignAPI.EnvelopeInformation ei = new DocusignAPI.EnvelopeInformation();
ei.AccountId = account_id;
ei.Subject = 'Lorem Ipsum';
ei.EmailBlurb = 'More text...';
// Create an envelope and fill it in
DocusignAPI.CustomField field = new DocusignAPI.CustomField ();
field.Name = 'DSFSSourceObjectId';
field.Value = 'a1qW0000000vMCj';
field.Show = 'false';
field.CustomFieldType = 'Text';
DocusignAPI.ArrayOfCustomField arrayOfCustomFields = new DocusignAPI.ArrayOfCustomField();
arrayOfCustomFields.CustomField = new list<DocusignAPI.CustomField>();
arrayOfCustomFields.CustomField.add(field);
ei.CustomFields = arrayOfCustomFields;
try {
DocusignAPI.EnvelopeStatus result = api_sender.CreateEnvelopeFromTemplates(templateReferences, recipients, ei, true);
envelope_id = result.EnvelopeID;
System.debug('Returned successfully, envelope_id = ' + envelope_id );
} catch ( CalloutException e) {
System.debug('Exception - ' + e );
error_code = 'Problem: ' + e;
error_message = error_code;
}
All customtags are related to my custom object with id defined in the CustomField above.
Any help gratefully appreciated.
Turns out I need to add in the object API name to the Id. Solution is:-
DocusignAPI.CustomField field = new DocusignAPI.CustomField ();
field.Name = 'DSFSSourceObjectId';
field.Value = 'a1qW0000000vMCj~Property__c';
field.Show = 'false';
field.CustomFieldType = 'Text';
I'm trying to read appointments from Outlook calendar using ExchangeServiceBinding but my solution takes appointments only from "default" outlook calendar and don't read from "sub calendars/custom calendars". Do you know how to define rest of the calendars or do you know better solution which contains all calendars?
Critical part is that solution shouldn't contain MAPI because of next use in web service.
My current code:
private static List<List<string>> ReadCalendarEvents(string email)
{
List<List<string>> calendarEvents = new List<List<string>>();
// Specify the request version.
esb.RequestServerVersionValue = new RequestServerVersion();
esb.RequestServerVersionValue.Version = ExchangeVersionType.Exchange2007;
// Form the FindItem request.
FindItemType findItemRequest = new FindItemType();
CalendarViewType calendarView = new CalendarViewType();
calendarView.StartDate = DateTime.Now.AddDays(-7);
calendarView.EndDate = DateTime.Now.AddDays(200);
calendarView.MaxEntriesReturned = 1000;
calendarView.MaxEntriesReturnedSpecified = true;
findItemRequest.Item = calendarView;
// Define which item properties are returned in the response.
ItemResponseShapeType itemProperties = new ItemResponseShapeType();
// Use the Default shape for the response.
//itemProperties.BaseShape = DefaultShapeNamesType.IdOnly;
itemProperties.BaseShape = DefaultShapeNamesType.AllProperties;
findItemRequest.ItemShape = itemProperties;
DistinguishedFolderIdType[] folderIDArray = new DistinguishedFolderIdType[1];
folderIDArray[0] = new DistinguishedFolderIdType();
folderIDArray[0].Id = DistinguishedFolderIdNameType.calendar;
//
folderIDArray[0].Mailbox = new EmailAddressType();
folderIDArray[0].Mailbox.EmailAddress = email;
findItemRequest.ParentFolderIds = folderIDArray;
// Define the traversal type.
findItemRequest.Traversal = ItemQueryTraversalType.Shallow;
try
{
// Send the FindItem request and get the response.
FindItemResponseType findItemResponse = esb.FindItem(findItemRequest);
// Access the response message.
ArrayOfResponseMessagesType responseMessages = findItemResponse.ResponseMessages;
ResponseMessageType[] rmta = responseMessages.Items;
int folderNumber = 0;
foreach (ResponseMessageType rmt in rmta)
{
// One FindItemResponseMessageType per folder searched.
FindItemResponseMessageType firmt = rmt as FindItemResponseMessageType;
if (firmt.RootFolder == null)
continue;
FindItemParentType fipt = firmt.RootFolder;
object obj = fipt.Item;
// FindItem contains an array of items.
if (obj is ArrayOfRealItemsType)
{
ArrayOfRealItemsType items =
(obj as ArrayOfRealItemsType);
if (items.Items == null)
{
folderNumber++;
}
else
{
foreach (ItemType it in items.Items)
{
if (it is CalendarItemType)
{
CalendarItemType cal = (CalendarItemType)it;
List<string> ce = new List<string>();
ce.Add(cal.Location);
ce.Add(cal.Start.ToShortDateString() + " " + cal.Start.ToShortTimeString());
ce.Add(cal.End.ToShortDateString() + " " + cal.End.ToShortTimeString());
ce.Add(cal.Subject);
if (cal.Organizer != null)
{
ce.Add(cal.Organizer.Item.Name);
}
calendarEvents.Add(ce);
Console.WriteLine(cal.Subject + " " + cal.Start.ToShortDateString() + " " + cal.Start.ToShortTimeString() + " " + cal.Location);
}
}
folderNumber++;
}
}
}
}
catch (Exception e)
{
throw;
}
finally
{
}
return calendarEvents;
}
In EWS you need to query one folder at a time, for non default folders you will first need to find the FolderId before you can then query the appointments (or items) within a Folder. To find all the Calendar folders in a Mailbox you need to use the FindFolder operation and create a restriction to limit the result to folder with a FolderClass of IPF.Appointment eg
// Create the request and specify the travesal type.
FindFolderType findFolderRequest = new FindFolderType();
findFolderRequest.Traversal = FolderQueryTraversalType.Deep;
// Define the properties that are returned in the response.
FolderResponseShapeType responseShape = new FolderResponseShapeType();
responseShape.BaseShape = DefaultShapeNamesType.Default;
findFolderRequest.FolderShape = responseShape;
// Identify which folders to search.
DistinguishedFolderIdType[] folderIDArray = new DistinguishedFolderIdType[1];
folderIDArray[0] = new DistinguishedFolderIdType();
folderIDArray[0].Id = DistinguishedFolderIdNameType.msgfolderroot;
IsEqualToType iet = new IsEqualToType();
PathToUnindexedFieldType FolderClass = new PathToUnindexedFieldType();
FolderClass.FieldURI = UnindexedFieldURIType.folderFolderClass;
iet.Item = FolderClass;
FieldURIOrConstantType constantType = new FieldURIOrConstantType();
ConstantValueType constantValueType = new ConstantValueType();
constantValueType.Value = "IPF.Appointment";
constantType.Item = constantValueType;
iet.FieldURIOrConstant = constantType;
// Add the folders to search to the request.
RestrictionType restriction = new RestrictionType();
restriction.Item = iet;
findFolderRequest.Restriction = restriction;
findFolderRequest.ParentFolderIds = folderIDArray;
try
{
// Send the request and get the response.
FindFolderResponseType findFolderResponse = esb.FindFolder(findFolderRequest);
// Get the response messages.
ResponseMessageType[] rmta = findFolderResponse.ResponseMessages.Items;
foreach (ResponseMessageType rmt in rmta)
{
// Cast to the correct response message type.
if (((FindFolderResponseMessageType)rmt).ResponseClass == ResponseClassType.Success) {
foreach (FolderType folder in ((FindFolderResponseMessageType)rmt).RootFolder.Folders) {
Console.WriteLine(folder.DisplayName);
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
You also might want to look at using the EWS Managed API which will save you greatly time and the amount of code you need to write
Cheers
Glen
Lead - gets converted to an Account , Contact and an Opportunity
I developed a trigger which shares an Opportunity and related Account with another Org of ours, and the piece i am missing is sharing the Contact along with this . Need some help for sharing the contact also.
Trigger autoforwardOpportunity on Opportunity(after insert) {
String UserName = UserInfo.getName();
String orgName = UserInfo.getOrganizationName();
List<PartnerNetworkConnection> connMap = new List<PartnerNetworkConnection>(
[select Id, ConnectionStatus, ConnectionName from PartnerNetworkConnection where ConnectionStatus = 'Accepted']
);
System.debug('Size of connection map: '+connMap.size());
List<PartnerNetworkRecordConnection> prncList = new List<PartnerNetworkRecordConnection>();
for(Integer i =0; i< Trigger.size; i++) {
Opportunity Opp = Trigger.new[i];
String acId = Opp.Id;
System.debug('Value of OpportunityId: '+acId);
for(PartnerNetworkConnection network : connMap) {
String cid = network.Id;
String status = network.ConnectionStatus;
String connName = network.ConnectionName;
String AssignedBusinessUnit = Opp.Assigned_Business_Unit__c;
System.debug('Connectin Details.......Cid:::'+cid+'Status:::'+Status+'ConnName:::'+connName+','+AssignedBusinessUnit);
if(AssignedBusinessUnit!=Null && (AssignedBusinessUnit.equalsIgnoreCase('IT') || AssignedBusinessUnit.equalsIgnoreCase('Proservia'))) {
// Send account to IT instance
PartnerNetworkRecordConnection newAccount = new PartnerNetworkRecordConnection();
newAccount.ConnectionId = cid;
newAccount.LocalRecordId = Opp.AccountId;
newAccount.SendClosedTasks = true;
newAccount.SendOpenTasks = true;
newAccount.SendEmails = true;
newAccount.RelatedRecords = 'Contact';
System.debug('Inserting New Record'+newAccount);
insert newAccount;
// Send opportunity to IT instance
PartnerNetworkRecordConnection newrecord = new PartnerNetworkRecordConnection();
newrecord.ConnectionId = cid;
newrecord.LocalRecordId = acId;
newrecord.SendClosedTasks = true;
newrecord.SendOpenTasks = true;
newrecord.SendEmails = true;
//newrecord.ParentRecordId = Opp.AccountId;
System.debug('Inserting New Record'+newrecord);
insert newrecord;
}
}
}
}
newrecord.RelatedRecords = 'Contact,Opportunity'; //etc
Im working on a MVC app.
When I call context.SaveChanges to update a specific records. The update is not registered in the database. I do not get any runtime error either. All in notice is that my Records is not updated. I still see the same values. Insert Functionality work Perfectly.
enter code here
public Admission Update(int stuid){
VDData.VidyaDaanEntities context = new VDData.VidyaDaanEntities();
VDData.Student_Master studentmaster = new VDData.Student_Master();
studentmaster.Student_ID = stuid;
studentmaster.Student_First_Name = this.FirstName;
studentmaster.Student_Middle_Name = this.MiddleName;
studentmaster.Student_Last_Name = this.LastName;
studentmaster.Student_Address_1 = this.Address;
studentmaster.Student_Address_2 = this.Address2;
studentmaster.Student_City = this.City;
studentmaster.Student_State = this.State;
studentmaster.Student_Pin_Code = this.Pincode;
context.SaveChanges(); // here it wont give any kind of error. it runs sucessfully. }
First get the entity you are going to update:
var entity = obj.GetEntity(id);
entity.col1 = "value";
context.SaveChanges(entity);
hope this will help.
It seems like you want to update, so your code should be
VDData.Student_Master studentmaster = context.Student_Masters.Single(p=>p.Student_ID == stuid);
And you should not change the Student_ID if it is the primary key.
public Admission Update(int stuid){
VDData.VidyaDaanEntities context = new VDData.VidyaDaanEntities();
//VDData.Student_Master studentmaster = new VDData.Student_Master();
//REPLACE WITH
VDData.Student_Master studentmaster = context.Student_Masters.Where(p=>p.Student_ID == stuid);
studentmaster.Student_ID = stuid;
studentmaster.Student_First_Name = this.FirstName;
studentmaster.Student_Middle_Name = this.MiddleName;
studentmaster.Student_Last_Name = this.LastName;
studentmaster.Student_Address_1 = this.Address;
studentmaster.Student_Address_2 = this.Address2;
studentmaster.Student_City = this.City;
studentmaster.Student_State = this.State;
studentmaster.Student_Pin_Code = this.Pincode;
context.SaveChanges();
Before
context.SaveChanges();
You need to call this
context.Student_Masters.Add(studentmaster );
Edit: introduce Abstraction to your Context class and Create a method in your context class like below, then you can call it whenever you want to create or update your objects.
public void SaveStudent_Master(Student_Master studentmaster)
{
using (var context = new VDData.VidyaDaanEntities())
{
if (studentmaster.Student_ID == 0)
{
context.Student_Masters.Add(studentmaster);
}
else if (studentmaster.Student_ID > 0)
{
//This Updates N-Level deep Object grapgh
//This is important for Updates
var currentStudent_Master = context.Student_Masters
.Single(s => s.Student_ID == studentmaster.Student_ID );
context.Entry(currentStudent_Master ).CurrentValues.SetValues(studentmaster);
}
context.SaveChanges();
}
Then in your Controller replace context.SaveChanges(); with _context.SaveStudent_Master(studentmaster);