talia_core 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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