How to show custom events to a Kronolith calendar - calendar

I want to show events from an external source in the Kronolith calendar views. I don't want to do this by exporting the events to iCal and then showing them as an external calendar. The events are grouped in multiple calendars, the user should be able to disable/enable these calendars.

You can do this by implementing the listTimeObjects and listTimeObjectCategories API calls. Nag (task list) and Whups (ticket tracking) do it this way. If you are using the Git version, you can use TimeObjects, which wraps everything up in a nice class.
Kronolith calls these functions in initialize() (when filling $all_external_calendars) and listEvents(). It searches all APIs for this function, so you can register it with your own prefix.
timeObject is a generic name for "things that can be shown on a calendar", like events, task due dates, ... A timeObjectCategory is a group of timeObjects, which can be enabled or disabled in a group by the user. (In the default layout: using the panel in the upper-right corner of the calendar view, "Calendars".)
Your implementation for listTimeObjectCategories should return an array, with a category id as the key, and the user-visible name as the value. The category id's are also shown at the bottom of the calendar, and the user can define colors for them.
listTimeObjects is called with the currently selected categories (an array of id's), and a start and end date. These dates might already be Horde_Date objects (to be sure, convert them again: $start = new Horde_Date($start)).
You should return an array of timeObjects that belong to these categories and fall in the specified time range. The keys are event id's, the values are arrays with values for the following keys:
id
title
description
start (Horde_Date or timestamp)
end (Horde_Date or timestamp)
category (Category id)
params
If you register the show API call, this will be used for creating the link to the timeObject detail.

Related

How do I create and save a set/array of objects for a given Core Data entity?

I have an app that will ideally compare luxury restaurants and their respective dishes against each other. This means I have a Core Data entity called Restaurant with attributes like restaurantName, location, averagePrice, and foodType. I have a second Core Data entity called MenuItem with attributes like foodName, caloryCount, price, and rating.
Since the goal is to compare, say, two steakhouses and their filet mignons on calories/price/rating, I'd really like to take a preloaded list of MenuItem objects I have (an array called selectedMenuItems) and somehow save that as an attribute of the Restaurant entity so that each individual restaurant will have an instance of those menu item objects attached to it (after which the user could edit the calories/price/rating for each menu item on a restaurant by restaurant basis). In the most ideal scenario, if anything was added or subtracted from the selectedMenuItems array of objects it would be reflected across all individual restaurants.
What I've tried so far:
1.) Many-to-many relationship between Restaurant and MenuItem
As you can probably guess from my above description, this didn't work out how I wanted it to since it only connected each restaurant to the selectedMenuItems array, and any alterations made in a restaurant propagated through the relationship to the array (this was a fundamental misunderstanding of relationships, on my part).
2.) Create an attribute of type Transformable in Restaurant to hold the selectedMenuItems array
This looked like it was going to work for a moment. As I said, I created an attribute called menuItems in my Restaurant entity of type Transformable, and then in the view controller for each restaurant's detail view (the view controller that displays the menuItems is an additional navigation step) I added the following inside of viewDidLoad():
// The selected Restaurant is passed from the prior screen to restaurant
restaurant.menuItems = selectedMenuItems as NSObject?
Which resulted in seemingly what I needed, except for the fact that if I made any changes to the selectedMenuItems array, it would cause the app to crash with the console readout 'NSInvalidArgumentException', reason: '-[Restaurant encodeWithCoder:]: unrecognized selector sent to instance.
3.) Break apart the selectedMenuItems array of objects into matched arrays of properties
After doing some experimenting with 2.), it appeared as though having an array of objects was the issue. Because of this, I iterated through selectedMenuItems and stripped out the properties into their own arrays (foodNameArray, caloryCountArray, priceArray, etc.). After that, I assigned each of those to newly created attributes of my Restaurant entity:
restaurant.foodNames = foodNameArray as NSObject?
restaurant.caloryCounts = caloryCountArray as NSObject?
restaurant.prices = priceArray as NSObject?
Now, this was already looking very dodgy and prone to catastrophic failure. It did, however, work pretty much how I wanted it to. The issue here was that any changes to selectedMenuItems (like adding/removing a new object) didn't pass through to my restaurants after the first load. This is in contrast with 1.) where the changes propagated from the restaurants to selectedMenuItems (bottom to top) compared to 3.), where I want the changes to flow top to bottom.
Given the above descriptions, does anyone have advice on how I can get the functionality I'm looking for?
Rather than a many-many relationship, I would use three entities:
Restaurant, as you currently have;
Dish, which represents the generic menu item, such as "Filet mignon" or "Rib-eye"; and
MenuItem, which is a particular Dish served by a particular Restaurant.
Because Dish is generic, it would have only one attribute foodName (though you might want others). MenuItem would have attributes caloryCount, price, rating.
Since each MenuItem represents a particular dish served by a particular restaurant, it would have "to-one" relationships to Restaurant and Dish. For each relationship, the inverse would be "to-many": a Restaurant will serve many MenuItems, and a Dish could feature in many MenuItems.
You can then preload the list of Dishes, from which users can select those which are served by a particular restaurant. You can then create corresponding MenuItems and can presumably let users record calories/price/rating. If the user deletes a MenuItem, the corresponding Dish is unaffected, so will be available for other existing and/or new Restaurants. If the user wants to add a MenuItem for which there is no existing Dish, you can add a new Dish, which will then be available for any subsequent MenuItems.

Mixpanel - How to sort users by descending datetime of a certain activity

I have around 100 users in my Mixpanel (each having distinct_id), and I send events A, B , C for users as and when they do specific things in the UI
How can sort users by the descending datetime of their performance of activity associated with an event, say event A?
The last seen property of an user gets updated only when i add or update a property of an user.
Thanks
At the moment it's not possible to relate event data to individual user profiles:
As of now, People and Engagement are two separate data sets. We're working on tying these data sets together more tightly, but for the moment they are not seamlessly integrated.
The workaround is to update the Mixpanel user profile every time you trigger an event and store the current date as a property like "LastTimeEventTriggered - ViewHomepage".
The easiest way to do this is by using a wrapper function instead of mixpanel.track:
function trackEvent(eventName, data){
mixpanel.track(eventName, data);
mixpanel.people.set({"LastTimeEventTriggered - " + eventName, new Date()})
}
trackEvent("ViewHomepage", {})

How to sync two models representing the same object but with a different cid?

In my app, user can create vehicles. On the "show specific vehicle" page, I have an instance of Vehicle (which extend RelationalModel from Backbone Relational). When I change the avatar of the vehicle, this model is changed.
In another page "show vehicles list" of the application, I have a gallery showing the vehicles of the user. The models (instances of Vehicle too) are in a collection. Unfortunately, they have a different CID and thus are not updated properly when the user changes the avatar of the Vehicle in the show Page.
How to deal with that? I would like the Vehicle #9 to be the same everywhere.
I would define an application-level vehicleCollection (A) where you store all vehicles you get from every single request that returns vehicles (B, C). Since every vehicleId will be the same, you can do a look-up in the main collection (A) if the model already exists when you loop over the resultset from the other collection fetch (B, C).
You will most likely need to work with temporary collections and inject the relevant model from the main collection (A)
If you look through the tests that come with the Backbone package (or just go to their github repo) you can clearly see how it works adding the same model to different collections

Why does EWS Managed API SyncFolderItems not return recurring appointments

I'm using the managed API of EWS to synchronize a scheduling application with exchange calendars. I get all normal meetings fine, but I am not getting any repeating/recurring appointments.
My code follows:
itemChangeCollection = _service.SyncFolderItems(
new FolderId(WellKnownFolderName.Calendar,
new Mailbox(Email)),
propertySet,
null,
Settings.Default.ExchangeSyncFetchCount,
SyncFolderItemsScope.NormalItems,
syncState);
What do I need to change to see the recurring appointments as well?
Instances of recurring appointments are not "real" items in the store. They are virtual in the sense that they are calculated whenever you perform a search with a calendar view and a timeframe.
The only way to find recurring appointments is to use the FindItems method.
SyncFolderItems only returns the necessary information to reconstruct a recurring serie but does not expand the individual occurrences. If you need expanded occurrences you need to use the FindItems method.
However, even assuming you can expand the recurrence yourself, SyncFolderItems alone does not provide all the necessary information.
SyncFolderItems will return a list of events with Single or RecurringMaster AppointmentType. A RecurringMaster event contains the ModifiedOccurrences and DeletedOccurrences properties. Unfortunately the items in ModifiedOccurrences only contains the ItemId, not the Item itself. It seems necessary to solve all exception separately to get the fields of modified occurrences. From the documentation:
Each OccurrenceInfo object in the ModifiedOccurrences collection
contains four properties: End, ItemId, OriginalStart, and Start. To
access additional properties on the exception item, you must bind to
the item by using the OccurrenceInfo.ItemId.
foreach (OccurrenceInfo item in recurringMasterItem.ModifiedOccurrences)
{
Appointment modifiedItem = Appointment.Bind(service, item.ItemId);
Console.WriteLine("Subject: " + modifiedItem.Subject);
}
In other words, with the data you get from SyncFolderItem you can expand a recurrence, including time exceptions and deleted occurrences but you would have to resolve exceptions on other fields (ie. summary, body, location. etc) with additional .Bind() calls.
SyncFolderItems will give you the recurring master items, but does not expand them into occurrences. The recurring master holds the common properties for all items, the recurring pattern and a list of exceptions and deletions. This is all the information required to expand them to occurrences. Although you are supposed to call Appointment.BindToOccurrence to bind the properties for an individual occurrence from a recurring master based on an occurrence index. The downside is this makes an EWS call for each occurrence.

Custom Button to copy data from Opportunity into a related custom object

I have a custom object that is used for product setup that is mapped to an opportunity. It's a one to many relationship - one opportunity maps to many setup objects, but one setup object is only mapped to one opportunity.
Opportunity has some setup fields that need to act as defaults for the related custom object. Unfortunately, I cannot just specify them in a formula - getting an error.
What I would like to do is have a custom button that would allow user to click and copy all of the related setup fields from the opportunity into the custom setup object and then edit them as needed.
Any pointers or sample code are greatly appreciated!
You can achieve this with a custom button on the related list for your custom object on the opportunity detail page.
All of the fields on a standard Salesforce new/edit screen have id's associated with them. You can specify values for fields by using these ids to set GET parameters on your URL. For example if the id on the name field on your opportunity is 'opp3', the following URL will populate the name field on your new opportunity page:
https://na2.salesforce.com/006/e?opp3=Hello+World
You would have to change na2 to the correct server for your org.
The new record page URL contains the 3 character id prefix for your particular object and then '/e'. 006 is the prefix for opportunities. You will have to attempt to create a new record to see what the 3 characters are for your custom object.
You will have to capture the id's of the fields you want to populate on your custom object. You can do this by viewing the source of the new record page. For custom fields these id's will take the form of a Salesforce Id (eg. 00N40000002QhEV).
Create a new list button on your custom object and set the behavior to without header and sidebar and set the source to URL. Build up your URL with id=value pairs separated by '&' using the id you got from the page source and the insert field functionality to select the opportunity fields your wish to add in. You should end up with something like this:
/a0U/e?00N40000002QhEV={!Opportunity.Name}&00N40000002QhEW={!Opportunity.StageName}
a0U should be replaced by the correct prefix for your custom object. Then add your button to the related list for your custom object under opportunity.

Resources