[folks] Add linking support to the IndividualAggregator
- From: Travis Reitter <treitter src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [folks] Add linking support to the IndividualAggregator
- Date: Tue, 3 Aug 2010 21:22:08 +0000 (UTC)
commit 4e73c105f32f683cdd51e269fb15262c7f345402
Author: Philip Withnall <philip withnall collabora co uk>
Date: Mon Jul 19 16:37:46 2010 +0100
Add linking support to the IndividualAggregator
Personas are linked together to form Individuals using a link map containing
mappings from UIDs and linkable properties to Individual instances. This
takes PersonaStore trust levels into account.
backends/key-file/kf-persona.vala | 25 +++++++++
folks/individual-aggregator.vala | 108 +++++++++++++++++++++++++++++-------
folks/persona.vala | 34 ++++++++++++
3 files changed, 146 insertions(+), 21 deletions(-)
---
diff --git a/backends/key-file/kf-persona.vala b/backends/key-file/kf-persona.vala
index 54b0a7e..a40dd0a 100644
--- a/backends/key-file/kf-persona.vala
+++ b/backends/key-file/kf-persona.vala
@@ -121,4 +121,29 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
GLib.assert_not_reached ();
}
}
+
+ public override void linkable_property_to_links (string prop_name,
+ Folks.Persona.LinkablePropertyCallback callback)
+ {
+ if (prop_name == "im-addresses")
+ {
+ this.im_addresses.foreach ((k, v) =>
+ {
+ unowned string protocol = (string) k;
+ unowned GenericArray<string> im_addresses =
+ (GenericArray<string>) v;
+
+ im_addresses.foreach ((v) =>
+ {
+ unowned string address = (string) v;
+ callback (protocol + ":" + address);
+ });
+ });
+ }
+ else
+ {
+ /* Chain up */
+ base.linkable_property_to_links (prop_name, callback);
+ }
+ }
}
diff --git a/folks/individual-aggregator.vala b/folks/individual-aggregator.vala
index 498b651..9f900e0 100644
--- a/folks/individual-aggregator.vala
+++ b/folks/individual-aggregator.vala
@@ -48,6 +48,7 @@ public class Folks.IndividualAggregator : Object
private BackendStore backend_store;
private HashMap<string, PersonaStore> stores;
private HashSet<Backend> backends;
+ private HashTable<string, Individual> link_map;
/**
* A table mapping { link Individual.id}s to their { link Individual}s.
@@ -101,6 +102,7 @@ public class Folks.IndividualAggregator : Object
this.stores = new HashMap<string, PersonaStore> ();
this.individuals = new HashTable<string, Individual> (str_hash,
str_equal);
+ this.link_map = new HashTable<string, Individual> (str_hash, str_equal);
this.backends = new HashSet<Backend> ();
@@ -200,35 +202,99 @@ public class Folks.IndividualAggregator : Object
Persona? actor,
Groups.ChangeReason reason)
{
- var individuals = new GLib.List<Individual> ();
- added.foreach ((persona) =>
+ GLib.List<Individual> new_individuals = new GLib.List<Individual> ();
+
+ added.foreach ((p) =>
{
- unowned Persona p = (Persona) persona;
+ unowned Persona persona = (Persona) p;
+ PersonaStoreTrust trust_level = persona.store.trust_level;
+ Individual candidate_ind = null;
+
+ /* If we don't trust the PersonaStore at all, we can't link the
+ * Persona to any existing Individual */
+ if (trust_level != PersonaStoreTrust.NONE)
+ candidate_ind = this.link_map.lookup (persona.uid);
- /* FIXME: correlate the new personas with each other and
- * the existing personas and existing Individuals;
- * update existing Individuals and create new ones as
- * necessary */
+ if (candidate_ind != null)
+ {
+ /* The Persona's UID matches a linkable field which is already in
+ * the link map, so we add the new Persona to that Individual. */
+ GLib.List<unowned Persona> personas =
+ candidate_ind.personas.copy ();
+ personas.append (persona);
+ candidate_ind.personas = personas;
+ }
+ else
+ {
+ /* The Persona doesn't match anything in the link map, so we
+ * create a new Individual for the Persona. */
+ GLib.List<Persona> personas = new GLib.List<Persona> ();
+ personas.prepend (persona);
+ candidate_ind = new Individual (personas);
+
+ /* Add the new Individual to the aggregator */
+ candidate_ind.removed.connect (this.individual_removed_cb);
+ new_individuals.prepend (candidate_ind);
+ this.individuals.insert (candidate_ind.id, candidate_ind);
+
+ /* Only add the Persona to the link map if we trust its UID. */
+ if (trust_level != PersonaStoreTrust.NONE)
+ this.link_map.insert (persona.uid, candidate_ind);
+ }
- var grouped_personas = new GLib.List<Persona> ();
- grouped_personas.prepend (p);
- var individual = new Individual (grouped_personas);
- individuals.prepend (individual);
+ /* Only allow linking on non-UID properties of the Persona if we fully
+ * trust the PersonaStore it came from. */
+ if (persona.store.trust_level == PersonaStoreTrust.FULL)
+ {
+ /* Insert maps from the Persona's linkable properties to the
+ * Individual. */
+ foreach (string prop_name in persona.linkable_properties)
+ {
+ unowned ObjectClass pclass = persona.get_class ();
+ if (pclass.find_property (prop_name) == null)
+ {
+ warning ("Unknown property '%s' in linkable property " +
+ "list.", prop_name);
+ continue;
+ }
+
+ persona.linkable_property_to_links (prop_name, (l) =>
+ {
+ this.link_map.insert ((string) l, candidate_ind);
+ });
+ }
+ }
});
- /* For each of the individuals constructed from the newly added personas,
- * if they don't exist in the aggregator's list of member individuals,
- * add them to it. */
- GLib.List<Individual> new_individuals = null;
- foreach (var i in individuals)
+ removed.foreach ((p) =>
{
- if (this.individuals.lookup (i.id) == null)
+ unowned Persona persona = (Persona) p;
+ PersonaStoreTrust trust_level = persona.store.trust_level;
+
+ if (trust_level != PersonaStoreTrust.NONE)
+ this.link_map.remove (persona.uid);
+
+ if (trust_level == PersonaStoreTrust.FULL)
{
- i.removed.connect (this.individual_removed_cb);
- new_individuals.prepend (i);
- this.individuals.insert (i.id, i);
+ /* Remove maps from the Persona's linkable properties to the
+ * Individual. */
+ foreach (string prop_name in persona.linkable_properties)
+ {
+ unowned ObjectClass pclass = persona.get_class ();
+ if (pclass.find_property (prop_name) == null)
+ {
+ warning ("Unknown property '%s' in linkable property " +
+ "list.", prop_name);
+ continue;
+ }
+
+ persona.linkable_property_to_links (prop_name, (l) =>
+ {
+ this.link_map.remove ((string) l);
+ });
+ }
}
- }
+ });
/* Signal the addition of new individuals to the aggregator */
if (new_individuals != null)
diff --git a/folks/persona.vala b/folks/persona.vala
index cb0d0f0..f79b1dd 100644
--- a/folks/persona.vala
+++ b/folks/persona.vala
@@ -67,4 +67,38 @@ public abstract class Folks.Persona : Object
* level is not { link PersonaStoreTrust.FULL}.
*/
public string[] linkable_properties { get; protected set; }
+
+ /**
+ * Callback into the aggregator to manipulate a link mapping.
+ *
+ * This is a callback provided by the { link IndividualAggregator} whenever
+ * a { link Persona.linkable_property_to_links} method is called, which should
+ * be called by the `linkable_property_to_links` implementation for each
+ * linkable-property-to-individual mapping it wants to add or remove in the
+ * aggregator.
+ */
+ public delegate void LinkablePropertyCallback (string link);
+
+ /* FIXME: This code should move to the IMable interface as a concrete
+ * method of the interface. However, that depends on bgo#624842 */
+ /**
+ * Produce one or more mapping strings for the given property's value.
+ *
+ * This is a virtual method, to be overridden by subclasses of { link Persona}
+ * who have linkable properties. Each of their linkable properties should be
+ * handled by their implementation of this function, examining the current
+ * value of the property and calling `callback` with one or more mapping
+ * strings for the property's value. Each of these mapping strings will be
+ * added to the { link IndividualAggregator}'s link map, related to the
+ * { link Individual} instance which contains this { link Persona}.
+ *
+ * @see Persona.linkable_properties
+ */
+ public virtual void linkable_property_to_links (string prop_name,
+ LinkablePropertyCallback callback)
+ {
+ /* Backend-specific Persona subclasses should override this if they have
+ * any linkable properties */
+ assert_not_reached ();
+ }
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]