talia_core 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. data/README.rdoc +41 -0
  2. data/bin/talia +33 -0
  3. data/lib/JXslt/jxslt.rb +60 -0
  4. data/lib/acts_as_roled.rb +11 -0
  5. data/lib/core_ext/platform.rb +9 -0
  6. data/lib/core_ext/string.rb +6 -0
  7. data/lib/core_ext.rb +1 -0
  8. data/lib/custom_template.rb +4 -0
  9. data/lib/loader_helper.rb +62 -0
  10. data/lib/mysql.rb +1214 -0
  11. data/lib/progressbar.rb +236 -0
  12. data/lib/role.rb +12 -0
  13. data/lib/talia_cl/command_line.rb +39 -0
  14. data/lib/talia_cl/commands/standalone/cl_options.rb +9 -0
  15. data/lib/talia_cl/commands/standalone/standalone_generate.rb +75 -0
  16. data/lib/talia_cl/commands/standalone.rb +25 -0
  17. data/lib/talia_cl/commands/talia_console/cl_options.rb +55 -0
  18. data/lib/talia_cl/commands/talia_console/console_commands.rb +37 -0
  19. data/lib/talia_cl/commands/talia_console/talia_commands.rb +131 -0
  20. data/lib/talia_cl/commands/talia_console.rb +47 -0
  21. data/lib/talia_cl/core_commands.rb +11 -0
  22. data/lib/talia_cl.rb +47 -0
  23. data/lib/talia_core/active_source.rb +372 -0
  24. data/lib/talia_core/active_source_parts/class_methods.rb +378 -0
  25. data/lib/talia_core/active_source_parts/predicate_handler.rb +89 -0
  26. data/lib/talia_core/active_source_parts/rdf.rb +131 -0
  27. data/lib/talia_core/active_source_parts/sql_helper.rb +36 -0
  28. data/lib/talia_core/active_source_parts/xml/base_builder.rb +47 -0
  29. data/lib/talia_core/active_source_parts/xml/generic_reader.rb +363 -0
  30. data/lib/talia_core/active_source_parts/xml/rdf_builder.rb +88 -0
  31. data/lib/talia_core/active_source_parts/xml/source_builder.rb +73 -0
  32. data/lib/talia_core/active_source_parts/xml/source_reader.rb +20 -0
  33. data/lib/talia_core/agent.rb +14 -0
  34. data/lib/talia_core/background_jobs/job.rb +82 -0
  35. data/lib/talia_core/background_jobs/progress_job.rb +68 -0
  36. data/lib/talia_core/collection.rb +13 -0
  37. data/lib/talia_core/data_types/data_loader.rb +92 -0
  38. data/lib/talia_core/data_types/data_record.rb +105 -0
  39. data/lib/talia_core/data_types/delayed_copier.rb +76 -0
  40. data/lib/talia_core/data_types/file_record.rb +59 -0
  41. data/lib/talia_core/data_types/file_store.rb +306 -0
  42. data/lib/talia_core/data_types/iip_data.rb +153 -0
  43. data/lib/talia_core/data_types/iip_loader.rb +127 -0
  44. data/lib/talia_core/data_types/image_data.rb +32 -0
  45. data/lib/talia_core/data_types/media_link.rb +19 -0
  46. data/lib/talia_core/data_types/mime_mapping.rb +45 -0
  47. data/lib/talia_core/data_types/path_helpers.rb +77 -0
  48. data/lib/talia_core/data_types/pdf_data.rb +42 -0
  49. data/lib/talia_core/data_types/simple_text.rb +36 -0
  50. data/lib/talia_core/data_types/temp_file_handling.rb +85 -0
  51. data/lib/talia_core/data_types/xml_data.rb +169 -0
  52. data/lib/talia_core/dc_resource.rb +20 -0
  53. data/lib/talia_core/dummy_handler.rb +34 -0
  54. data/lib/talia_core/dummy_source.rb +20 -0
  55. data/lib/talia_core/errors.rb +25 -0
  56. data/lib/talia_core/initializer.rb +427 -0
  57. data/lib/talia_core/ordered_source.rb +228 -0
  58. data/lib/talia_core/rails_ext/actionpack/action_controller/record_identifier.rb +13 -0
  59. data/lib/talia_core/rails_ext/actionpack/action_controller.rb +1 -0
  60. data/lib/talia_core/rails_ext/actionpack.rb +1 -0
  61. data/lib/talia_core/rails_ext.rb +1 -0
  62. data/lib/talia_core/rdf_import.rb +90 -0
  63. data/lib/talia_core/rdf_resource.rb +159 -0
  64. data/lib/talia_core/semantic_collection_item.rb +93 -0
  65. data/lib/talia_core/semantic_collection_wrapper.rb +324 -0
  66. data/lib/talia_core/semantic_property.rb +7 -0
  67. data/lib/talia_core/semantic_relation.rb +67 -0
  68. data/lib/talia_core/source.rb +323 -0
  69. data/lib/talia_core/source_transfer_object.rb +38 -0
  70. data/lib/talia_core/workflow/base.rb +15 -0
  71. data/lib/talia_core/workflow/publication_workflow.rb +62 -0
  72. data/lib/talia_core/workflow.rb +300 -0
  73. data/lib/talia_core.rb +9 -0
  74. data/lib/talia_dependencies.rb +12 -0
  75. data/lib/talia_util/bar_progressor.rb +15 -0
  76. data/lib/talia_util/configuration/config_file.rb +48 -0
  77. data/lib/talia_util/configuration/database_config.rb +40 -0
  78. data/lib/talia_util/configuration/mysql_database_setup.rb +104 -0
  79. data/lib/talia_util/data_import.rb +91 -0
  80. data/lib/talia_util/image_conversions.rb +82 -0
  81. data/lib/talia_util/import_job_helper.rb +132 -0
  82. data/lib/talia_util/io_helper.rb +54 -0
  83. data/lib/talia_util/progressable.rb +38 -0
  84. data/lib/talia_util/progressbar.rb +236 -0
  85. data/lib/talia_util/rdf_update.rb +80 -0
  86. data/lib/talia_util/some_sigla.xml +1960 -0
  87. data/lib/talia_util/test_helpers.rb +151 -0
  88. data/lib/talia_util/util.rb +226 -0
  89. data/lib/talia_util/yaml_import.rb +80 -0
  90. data/lib/talia_util.rb +13 -0
  91. data/lib/user.rb +116 -0
  92. data/lib/version.rb +15 -0
  93. data/test/core_ext/string_test.rb +11 -0
  94. data/test/custom_template_test.rb +8 -0
  95. data/test/talia_core/active_source_predicate_test.rb +54 -0
  96. data/test/talia_core/active_source_rdf_test.rb +89 -0
  97. data/test/talia_core/active_source_test.rb +631 -0
  98. data/test/talia_core/data_types/data_loader_test.rb +123 -0
  99. data/test/talia_core/data_types/data_record_test.rb +40 -0
  100. data/test/talia_core/data_types/file_record_test.rb +171 -0
  101. data/test/talia_core/data_types/iip_data_test.rb +130 -0
  102. data/test/talia_core/data_types/image_data_test.rb +88 -0
  103. data/test/talia_core/data_types/pdf_data_test.rb +68 -0
  104. data/test/talia_core/data_types/xml_data_test.rb +134 -0
  105. data/test/talia_core/generic_xml_test.rb +83 -0
  106. data/test/talia_core/initializer_test.rb +36 -0
  107. data/test/talia_core/ordered_source_test.rb +398 -0
  108. data/test/talia_core/rdf_resource_test.rb +115 -0
  109. data/test/talia_core/semantic_collection_item_test.rb +129 -0
  110. data/test/talia_core/source_reader_test.rb +33 -0
  111. data/test/talia_core/source_test.rb +484 -0
  112. data/test/talia_core/source_transfer_object_test.rb +24 -0
  113. data/test/talia_core/workflow/publication_workflow_test.rb +242 -0
  114. data/test/talia_core/workflow/user_class_for_workflow.rb +35 -0
  115. data/test/talia_core/workflow/workflow_base_test.rb +21 -0
  116. data/test/talia_core/workflow_test.rb +19 -0
  117. data/test/talia_util/import_job_helper_test.rb +46 -0
  118. data/test/test_helper.rb +68 -0
  119. metadata +262 -0
@@ -0,0 +1,67 @@
1
+ module TaliaCore
2
+ class SemanticRelation < ActiveRecord::Base
3
+ belongs_to :subject, :class_name => 'ActiveSource'
4
+ belongs_to :object, :polymorphic => true
5
+ before_destroy :discard_property
6
+
7
+ # Returns true if the Relation matches the given predicate URI (and value,
8
+ # if given)
9
+ def matches?(predicate, value = nil)
10
+ if(value)
11
+ if(value.is_a?(ActiveSource) || value.is_a?(SemanticProperty))
12
+ (predicate_uri == predicate.to_s) && (value == object)
13
+ else
14
+ return false unless(object.is_a?(SemanticProperty))
15
+ (predicate_uri == predicate.to_s) && (object.value == value)
16
+ end
17
+ else
18
+ predicate_uri == predicate.to_s
19
+ end
20
+ end
21
+
22
+ class << self
23
+
24
+ # Retrieve "fat" relations for the given source and property
25
+ def find_fat_relations(source, predicate)
26
+ joins = ActiveSource.sources_join
27
+ joins << ActiveSource.props_join
28
+ relations = SemanticRelation.find(:all, :conditions => {
29
+ :subject_id => source.id,
30
+ :predicate_uri => predicate
31
+ },
32
+ :joins => joins,
33
+ :select => fat_record_select
34
+ )
35
+ relations
36
+ end
37
+
38
+ # For selecting "fat" records on the semantic properties
39
+ def fat_record_select
40
+ @select ||= begin
41
+ select = 'semantic_relations.id AS id, semantic_relations.created_at AS created_at, '
42
+ select << 'semantic_relations.updated_at AS updated_at, '
43
+ select << 'semantic_relations.rel_order AS rel_order,'
44
+ select << 'object_id, object_type, subject_id, predicate_uri, '
45
+ select << 'obj_props.created_at AS property_created_at, '
46
+ select << 'obj_props.updated_at AS property_updated_at, '
47
+ select << 'obj_props.value AS property_value, '
48
+ select << 'obj_sources.created_at AS object_created_at, '
49
+ select << 'obj_sources.updated_at AS object_updated_at, obj_sources.type AS object_realtype, '
50
+ select << 'obj_sources.uri AS object_uri'
51
+ select
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ private
58
+
59
+ # Discards the "value" property that belongs to this source
60
+ def discard_property
61
+ if(object.is_a?(SemanticProperty))
62
+ SemanticProperty.delete(object.id)
63
+ end
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,323 @@
1
+ # require 'objectproperties' # Includes the class methods for the object_properties
2
+ require 'source_transfer_object'
3
+ require 'active_rdf'
4
+ require 'semantic_naming'
5
+ require 'dummy_handler'
6
+ require 'rdf_resource'
7
+
8
+ module TaliaCore
9
+
10
+ # This represents a Source in the Talia core system.
11
+ #
12
+ # Since data for the Source exists both in the database and in the RDF store, the
13
+ # handling/saving of data is a bit peculiar at the moment (subject to change in the future):
14
+ #
15
+ # * When a new Source is created, no data is saved
16
+ # * RDF properties *cannot* be written until the Source has been saved for the first time
17
+ # * Database properties are *only* written when the save method is called
18
+ # * RDF properties are written immediately when they are assigned
19
+ # * To ensure that the data is written, the save method should be called as
20
+ # necessary.
21
+ class Source < ActiveSource
22
+
23
+ has_one :workflow, :class_name => 'TaliaCore::Workflow::Base', :dependent => :destroy
24
+
25
+ # The uri will be wrapped into an object
26
+ def uri
27
+ N::URI.new(self[:uri])
28
+ end
29
+
30
+ # Indicates if this source belongs to the local store
31
+ def local
32
+ uri.local?
33
+ end
34
+
35
+ alias_method :ar_update_attributes, :update_attributes
36
+ # Wrapping for <tt>ActiveRecord</tt> <tt>update_attributes</tt>.
37
+ def update_attributes(attributes)
38
+ attributes, rdf_attributes = extract_attributes!(attributes)
39
+ rdf_attributes.each do |k,v|
40
+ send(k + "=", v)
41
+ send('save_' + k)
42
+ end
43
+ end
44
+
45
+ # Shortcut for assigning the primary_source status
46
+ def primary_source=(value)
47
+ value = value ? 'true' : 'false'
48
+ predicate_set(:talia, :primary_source, value)
49
+ end
50
+
51
+ # Indicates if the current source is considered "primary" in the local
52
+ # library
53
+ def primary_source
54
+ predicate(:talia, :primary_source) == true
55
+ end
56
+
57
+ # Searches for sources where <tt>property</tt> has one of the values given
58
+ # to this method. The result is a hash that contains one result list for
59
+ # each of the values, with the value as a key.
60
+ #
61
+ # This performs a find operation for each value, and the params passed
62
+ # to this method are added to the find parameters for each of those finds.
63
+ #
64
+ # *Example*
65
+ #
66
+ # # Returns all Sources that are of the RDFS type Class or Property. This
67
+ # # will return a hash with 2 lists (one for the Classes, and one for the
68
+ # # properties, and each list will be limited to 5 elements.
69
+ # Source.groups_by_property(N::RDF::type, [N::RDFS.Class, N::RDFS.Property], :limit => 5)
70
+ def self.groups_by_property(property, values, params = {})
71
+ # First create the joins
72
+ joins = 'LEFT JOIN semantic_relations ON semantic_relations.subject_id = active_sources.id '
73
+ joins << "LEFT JOIN active_sources AS t_sources ON semantic_relations.object_id = t_sources.id AND semantic_relations.object_type = 'TaliaCore::ActiveSource' "
74
+ joins << "LEFT JOIN semantic_properties ON semantic_relations.object_id = semantic_properties.id AND semantic_relations.object_type = 'TaliaCore::SemanticProperty' "
75
+
76
+ property = uri_string_for(property)
77
+ results = {}
78
+ for val in values
79
+ find(:all )
80
+ val_str = uri_string_for(val)
81
+ find_parms = params.merge(
82
+ :conditions => ['semantic_properties.value = ? OR t_sources.uri = ?', val_str, val_str],
83
+ :joins => joins
84
+ )
85
+ results[val] = find(:all, find_parms)
86
+ end
87
+
88
+ results
89
+ end
90
+
91
+ # Try to find a source for the given uri, if not exists it instantiate
92
+ # a new one, combining the N::LOCAL namespace and the given local name
93
+ #
94
+ # Example:
95
+ # ActiveSource.find_or_instantiate_by_uri('http://talia.org/existent')
96
+ # # => #<TaliaCore::ActiveSource id: 1, uri: "http://talia.org/existent">
97
+ #
98
+ # ActiveSource.find_or_instantiate_by_uri('http://talia.org/unexistent', 'Foo Bar')
99
+ # # => #<TaliaCore::ActiveSource id: nil, uri: "http://talia.org/Foo_Bar">
100
+ def self.find_or_instantiate_by_uri(uri, local_name)
101
+ result = find_by_uri(uri)
102
+ result ||= self.new(N::LOCAL.to_s + local_name.to_permalink)
103
+ end
104
+
105
+ # Find a list of sources which contains the given token inside the local name.
106
+ # This means that the namespace it will be excluded.
107
+ #
108
+ # Sources in system:
109
+ # * http://talia.org/one
110
+ # * http://talia.org/two
111
+ #
112
+ # Source.find_by_uri_token('a') # => [ ]
113
+ # Source.find_by_uri_token('o') # => [ 'http://talia.org/one', 'http://talia.org/two' ]
114
+ #
115
+ # NOTE: It internally use a MySQL function, as sql condition, to find the local name of the uri.
116
+ def self.find_by_uri_token(token, options = {})
117
+ find(:all, {
118
+ :conditions => [ "LOWER(SUBSTRING_INDEX(uri, '/', -1)) LIKE ?", '%' + token.downcase + '%' ],
119
+ :select => :uri,
120
+ :order => "uri ASC",
121
+ :limit => 10 }.merge!(options))
122
+ end
123
+
124
+ # Find the fist Source that matches the given URI.
125
+ # It's useful for admin pane, because users visit:
126
+ # /admin/sources/<source_id>/edit
127
+ # but that information is not enough, since we store
128
+ # into the database the whole reference as URI:
129
+ # http://localnode.org/av_media_sources/source_id
130
+ def self.find_by_partial_uri(id)
131
+ find(:first, :conditions => ["uri LIKE ?", '%' + id + '%'])
132
+ end
133
+
134
+ # Return an hash of direct predicates, grouped by namespace.
135
+ def grouped_direct_predicates
136
+ #TODO should it be memoized?
137
+ direct_predicates.inject({}) do |result, predicate|
138
+ predicates = self[predicate].collect { |p| SourceTransferObject.new(p.to_s) }
139
+ namespace = predicate.namespace.to_s
140
+ result[namespace] ||= {}
141
+ result[namespace][predicate.local_name] ||= []
142
+ result[namespace][predicate.local_name] << predicates
143
+ result
144
+ end
145
+ end
146
+
147
+ def predicate_objects(namespace, name) #:nodoc:
148
+ predicate(namespace, name).values.flatten.map(&:to_s)
149
+ end
150
+
151
+ # Check if the current source is related with the given rdf object (triple endpoint).
152
+ def associated?(namespace, name, stringified_predicate)
153
+ predicate_objects(namespace, name).include?(stringified_predicate)
154
+ end
155
+
156
+ # Check if a predicate is changed.
157
+ def predicate_changed?(namespace, name, objects)
158
+ not predicate_objects(namespace, name).eql?(objects.map(&:to_s))
159
+ end
160
+
161
+ attr_reader :predicates_attributes
162
+ def predicates_attributes=(predicates_attributes)
163
+ @predicates_attributes = predicates_attributes.collect do |attributes_hash|
164
+ attributes_hash['object'] = instantiate_source_or_rdf_object(attributes_hash)
165
+ attributes_hash
166
+ end
167
+ end
168
+
169
+ # Return an hash of new predicated attributes, grouped by namespace.
170
+ def grouped_predicates_attributes
171
+ @grouped_predicates_attributes ||= predicates_attributes.inject({}) do |result, predicate|
172
+ namespace, name = predicate['namespace'], predicate['name']
173
+ predicate = SourceTransferObject.new(predicate['titleized'])
174
+ result[namespace] ||= {}
175
+ result[namespace][name] ||= []
176
+ result[namespace][name] << predicate
177
+ result
178
+ end
179
+ end
180
+
181
+ # Save, associate/disassociate given predicates attributes.
182
+ def save_predicates_attributes
183
+ each_predicate do |namespace, name, objects|
184
+ objects.each { |object| object.save if object.is_a?(Source) && object.new_record? }
185
+ self.predicate_replace(namespace, name, objects.to_s) if predicate_changed?(namespace, name, objects)
186
+ end
187
+ end
188
+
189
+
190
+ # Returns an array of labels for this source. You may give the name of the
191
+ # property that is used as a label, by default it uses rdf:label(s). If
192
+ # the given property is not set, it will return the local part of this
193
+ # Source's URI.
194
+ #
195
+ # In any case, the result will always be an Array with at least one elment.
196
+ def labels(type = N::RDFS::label)
197
+ labels = get_attribute(type)
198
+ unless(labels && labels.size > 0)
199
+ labels = [uri.local_name]
200
+ end
201
+
202
+ labels
203
+ end
204
+
205
+ # This returns a single label of the given type. (If multiple labels
206
+ # exist in the RDF, just the first is returned.)
207
+ def label(type = N::RDFS::label)
208
+ labels(type)[0]
209
+ end
210
+
211
+ # Return the titleized uri local name.
212
+ #
213
+ # http://localnode.org/source # => Source
214
+ def titleized
215
+ self.uri.local_name.titleize
216
+ end
217
+
218
+ # Equality test. Two sources are equal if they have the same URI
219
+ def ==(value)
220
+ value.is_a?(Source) && (value.uri == uri)
221
+ end
222
+
223
+ def normalize_uri(uri, label = '')
224
+ self.class.normalize_uri(uri, label)
225
+ end
226
+
227
+ protected
228
+
229
+ # Separates given attributes distinguishing between ActiveSource and RDF.
230
+ def extract_attributes!(attributes)
231
+ active_source_attributes = attributes.inject({}) do |active_source_attributes, column_values|
232
+ active_source_attributes[column_values.first] = attributes.delete(column_values.first) if self.class.column_names.include? column_values.first
233
+ active_source_attributes
234
+ end
235
+
236
+ [ active_source_attributes, attributes ]
237
+ end
238
+
239
+ # Look at the given attributes and choose to instantiate
240
+ # a Source or a RDF object (triple endpoint).
241
+ #
242
+ # Cases:
243
+ # Homer Simpson
244
+ # # => Should instantiate a source with
245
+ # http://localnode.org/Homer_Simpson using N::LOCAL constant.
246
+ #
247
+ # "Homer Simpson"
248
+ # # => Should return the string itself, without the double quoting
249
+ # in order to add it directly to the RDF triple.
250
+ #
251
+ # http://springfield.org/Homer_Simpson
252
+ # # => Should instantiate a source with the given uri
253
+ def instantiate_source_or_rdf_object(attributes)
254
+ name_or_uri = attributes['titleized']
255
+ if /^\"[\w\s\d]+\"$/.match name_or_uri
256
+ name_or_uri[1..-2]
257
+ elsif attributes['uri'].blank? and attributes['source'].blank?
258
+ name_or_uri
259
+ elsif /^http:\/\//.match name_or_uri
260
+ Source.new(name_or_uri)
261
+ else
262
+ Source.find_or_instantiate_by_uri(normalize_uri(attributes['uri']), name_or_uri)
263
+ end
264
+ end
265
+
266
+ # Iterate through grouped_predicates_attributes, yielding the given code.
267
+ def each_predicate(&block)
268
+ grouped_predicates_attributes.each do |namespace, predicates|
269
+ predicates.each do |predicate, objects|
270
+ block.call(namespace, predicate, objects.flatten)
271
+ end
272
+ end
273
+ end
274
+
275
+ # Class methods
276
+ class << self
277
+
278
+ # Normalize the given uri.
279
+ #
280
+ # Example:
281
+ # normalize_uri('Lucca') # => http://www.talia.discovery-project.org/sources/Lucca
282
+ # normalize_uri('http://xmlns.com/foaf/0.1/Group') # => http://xmlns.com/foaf/0.1/Group
283
+ # normalize_uri('http://www.talia.discovery-project.org/sources/Lucca')
284
+ # # => http://www.talia.discovery-project.org/sources/Lucca
285
+ def normalize_uri(uri, label = '')
286
+ uri = N::LOCAL if uri.blank?
287
+ uri = N::LOCAL+label.gsub(' ', '_') if uri == N::LOCAL.to_s
288
+ uri.to_s
289
+ end
290
+
291
+ end
292
+
293
+ # End of class methods
294
+
295
+
296
+ # Missing methods: This just check if the given method corresponds to a
297
+ # registered namespace. If yes, this will return a "dummy" handler that
298
+ # allows access to properties.
299
+ #
300
+ # This will allow invocations as namespace::name
301
+ def method_missing(method_name, *args)
302
+ # TODO: Add permission checking for all updates to the model
303
+ # TODO: Add permission checking for read access?
304
+
305
+ update = method_name.to_s[-1..-1] == '='
306
+
307
+ shortcut = if update
308
+ method_name.to_s[0..-2]
309
+ else
310
+ method_name.to_s
311
+ end
312
+
313
+ # Otherwise, check for the RDF predicate
314
+ registered = N::URI[shortcut.to_s]
315
+
316
+ return super(method_name, *args) unless(registered) # normal handler if not a registered uri
317
+ raise(ArgumentError, "Must give a namspace as argument") unless(registered.is_a?(N::Namespace))
318
+
319
+ DummyHandler.new(registered, self)
320
+ end
321
+
322
+ end
323
+ end
@@ -0,0 +1,38 @@
1
+ module TaliaCore #:nodoc:
2
+ # Transfer Object Pattern implementation.
3
+ # It's required by source administration panel, in order to normalize
4
+ # the values transportation between view and controller layers.
5
+ #
6
+ # RDF objects (triple endpoint), could be a Source or a String.
7
+ #
8
+ # http://java.sun.com/blueprints/corej2eepatterns/Patterns/TransferObject.html
9
+ # http://java.sun.com/blueprints/patterns/TransferObject.html
10
+ class SourceTransferObject
11
+ attr_reader :uri
12
+
13
+ def initialize(name_or_uri) #:nodoc:
14
+ @uri, @name = if /http:\/\//.match name_or_uri
15
+ uri = N::URI.new(name_or_uri)
16
+ [uri, uri.local_name]
17
+ else
18
+ [nil, name_or_uri]
19
+ end
20
+ end
21
+
22
+ def id
23
+ @name
24
+ end
25
+
26
+ def source?
27
+ !uri.blank?
28
+ end
29
+
30
+ def titleized #:nodoc:
31
+ @name.titleize
32
+ end
33
+
34
+ def to_s #:nodoc:
35
+ (uri || @name).to_s
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ require File.join('talia_core', 'workflow')
2
+
3
+ module TaliaCore
4
+ module Workflow
5
+ # Workflow Record class.
6
+ class Base < ActiveRecord::Base
7
+
8
+ set_table_name 'workflows'
9
+ belongs_to :source
10
+
11
+ include TaliaCore::Workflow
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,62 @@
1
+ module TaliaCore
2
+
3
+ module Workflow
4
+
5
+ class PublicationWorkflow < Base
6
+
7
+ workflow_machine :initial => :submitted, :initial_properties => {:vote => 0}, :column => 'state', :properties => 'arguments'
8
+
9
+ state :submitted
10
+ state :accepted
11
+ state :rejected
12
+ state :published
13
+
14
+ event :vote, :require_role => :reviewer do
15
+ transitions :from => :submitted, :to => :submitted,
16
+ :guard => :is_submittable?,
17
+ :on_transition => :vote
18
+ transitions :from => :submitted, :to => :accepted,
19
+ :guard => :is_acceptable?,
20
+ :on_transition => :vote
21
+ transitions :from => :submitted, :to => :rejected,
22
+ :guard => :is_rejectable?,
23
+ :on_transition => :vote
24
+ end
25
+
26
+ event :direct_publish, :require_role => :admin do
27
+ transitions :from => :submitted, :to => :published
28
+ end
29
+
30
+ event :publish, :require_role => :editor do
31
+ transitions :from => :accepted, :to => :published
32
+ end
33
+
34
+ private
35
+
36
+ # vote method is called by transition
37
+ #
38
+ # Syntax example:
39
+ # record.vote!(my_user, 10)
40
+ def vote(value)
41
+ args = self.state_properties
42
+ args[:vote] += value[0]
43
+ self.state_properties=args
44
+ end
45
+
46
+ def is_submittable?(value)
47
+ vote = self.state_properties[:vote] + value[0]
48
+ (vote >= 0) && (vote <= 5)
49
+ end
50
+
51
+ def is_acceptable?(value)
52
+ (self.state_properties[:vote] + value[0]) > 5
53
+ end
54
+
55
+ def is_rejectable?(value)
56
+ (self.state_properties[:vote] + value[0]) < 0
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+ end