popolo 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +41 -0
- data/Rakefile +16 -0
- data/app/assets/javascripts/popolo/application.js +13 -0
- data/app/assets/stylesheets/popolo/application.css +13 -0
- data/app/controllers/popolo/areas_controller.rb +48 -0
- data/app/controllers/popolo/organizations_controller.rb +48 -0
- data/app/controllers/popolo/people_controller.rb +12 -0
- data/app/controllers/popolo/posts_controller.rb +12 -0
- data/app/controllers/popolo_controller.rb +3 -0
- data/app/helpers/popolo_helper.rb +10 -0
- data/app/models/popolo/address.rb +27 -0
- data/app/models/popolo/area.rb +25 -0
- data/app/models/popolo/event.rb +46 -0
- data/app/models/popolo/identifier.rb +15 -0
- data/app/models/popolo/link.rb +16 -0
- data/app/models/popolo/membership.rb +25 -0
- data/app/models/popolo/organization.rb +32 -0
- data/app/models/popolo/other_name.rb +21 -0
- data/app/models/popolo/person.rb +49 -0
- data/app/models/popolo/post.rb +25 -0
- data/app/models/popolo/source.rb +29 -0
- data/app/views/popolo/areas/index.html.erb +1 -0
- data/app/views/popolo/areas/show.html.erb +1 -0
- data/app/views/popolo/areas_or_organizations/_index.html.erb +31 -0
- data/app/views/popolo/areas_or_organizations/_show.html.erb +30 -0
- data/app/views/popolo/organizations/index.html.erb +1 -0
- data/app/views/popolo/organizations/show.html.erb +1 -0
- data/app/views/popolo/people/index.html.erb +0 -0
- data/app/views/popolo/people/show.html.erb +0 -0
- data/app/views/popolo/posts/index.html.erb +0 -0
- data/app/views/popolo/posts/show.html.erb +0 -0
- data/config/routes.rb +15 -0
- data/lib/generators/popolo_generator.rb +36 -0
- data/lib/generators/templates/README +7 -0
- data/lib/popolo/engine.rb +7 -0
- data/lib/popolo/mixins/eventable.rb +15 -0
- data/lib/popolo/mixins/sluggable.rb +64 -0
- data/lib/popolo/version.rb +3 -0
- data/lib/popolo.rb +18 -0
- data/spec/controllers/popolo/areas_controller_spec.rb +59 -0
- data/spec/controllers/popolo/organizations_controller_spec.rb +59 -0
- data/spec/controllers/popolo/people_controller_spec.rb +30 -0
- data/spec/controllers/popolo/posts_controller_spec.rb +30 -0
- data/spec/controllers/popolo_controller_spec.rb +4 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/cat.rb +6 -0
- data/spec/dummy/app/models/dog.rb +10 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config/application.rb +62 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/mongoid.yml +68 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/log/development.log +6 -0
- data/spec/dummy/log/test.log +35513 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories.rb +25 -0
- data/spec/helpers/popolo_helper_spec.rb +4 -0
- data/spec/models/popolo/address_spec.rb +4 -0
- data/spec/models/popolo/area_spec.rb +4 -0
- data/spec/models/popolo/event_spec.rb +7 -0
- data/spec/models/popolo/identifier_spec.rb +5 -0
- data/spec/models/popolo/link_spec.rb +5 -0
- data/spec/models/popolo/membership_spec.rb +27 -0
- data/spec/models/popolo/organization_spec.rb +25 -0
- data/spec/models/popolo/other_name_spec.rb +25 -0
- data/spec/models/popolo/person_spec.rb +25 -0
- data/spec/models/popolo/post_spec.rb +5 -0
- data/spec/models/popolo/source_spec.rb +7 -0
- data/spec/popolo/mixins/sluggable_spec.rb +153 -0
- data/spec/popolo_spec.rb +4 -0
- data/spec/routing/popolo/areas_routing_spec.rb +29 -0
- data/spec/routing/popolo/organizations_routing_spec.rb +29 -0
- data/spec/routing/popolo/people_routing_spec.rb +21 -0
- data/spec/routing/popolo/posts_routing_spec.rb +21 -0
- data/spec/spec_helper.rb +81 -0
- metadata +416 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Open North Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Popolo
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/opennorth/popolo.png)](http://travis-ci.org/opennorth/popolo)
|
4
|
+
[![Dependency Status](https://gemnasium.com/opennorth/popolo.png)](https://gemnasium.com/opennorth/popolo)
|
5
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/opennorth/popolo)
|
6
|
+
|
7
|
+
Popolo's goal is to make it easier for civic developers to create government transparency, monitoring and engagement websites.
|
8
|
+
|
9
|
+
Popolo is a [Ruby on Rails engine](http://guides.rubyonrails.org/engines.html) that provides additional functionality to a [Ruby on Rails](http://rubyonrails.org/) application, so that developers can focus on what's special about the governments they want to monitor, instead of re-implementing features commonly found in open government websites. The core Popolo engine provides basic models, controllers and views for the objects found in all open government websites – people, organizations and the relationships between the two. Other engines provide additional functionality.
|
10
|
+
|
11
|
+
In addition to being a Rails engine, Popolo is also a [data standard](http://popoloproject.com/data.html) and an [API specification](http://popoloproject.com/api.html).
|
12
|
+
|
13
|
+
## Getting Started
|
14
|
+
|
15
|
+
Popolo uses Mongoid to connect to MongoDB, which requires Rails 3 and supports only MRI 1.9.3 and HEAD, and JRuby 1.6.0+ in 1.9 mode.
|
16
|
+
|
17
|
+
First, create your Rails application:
|
18
|
+
|
19
|
+
rails new myapp --skip-active-record
|
20
|
+
|
21
|
+
Add the `popolo` gem to your `Gemfile`:
|
22
|
+
|
23
|
+
gem 'popolo'
|
24
|
+
|
25
|
+
If you didn't run `rails new` with the `--skip-active-record` option, follow Mongoid's [installation instructions](http://mongoid.org/en/mongoid/docs/installation.html). Otherwise:
|
26
|
+
|
27
|
+
rails generate mongoid:config
|
28
|
+
|
29
|
+
Finally, run the `popolo` generator:
|
30
|
+
|
31
|
+
rails generate popolo
|
32
|
+
|
33
|
+
## Bugs? Questions?
|
34
|
+
|
35
|
+
This engine's main repository is on GitHub: [http://github.com/opennorth/popolo](http://github.com/opennorth/popolo), where your contributions, forks, bug reports, feature requests, and feedback are greatly welcomed.
|
36
|
+
|
37
|
+
## Acknowledgements
|
38
|
+
|
39
|
+
This gem is developed by [Open North](http://www.opennorth.ca/) through a partnership with the [Participatory Politics Foundation](http://www.participatorypolitics.org/).
|
40
|
+
|
41
|
+
Copyright (c) 2012 Open North Inc., released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'yard'
|
11
|
+
YARD::Rake::YardocTask.new
|
12
|
+
rescue LoadError
|
13
|
+
task :yard do
|
14
|
+
abort 'YARD is not available. In order to run yard, you must: gem install yard'
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// the compiled file.
|
9
|
+
//
|
10
|
+
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
11
|
+
// GO AFTER THE REQUIRES BELOW.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Popolo
|
2
|
+
class AreasController < PopoloController
|
3
|
+
inherit_resources
|
4
|
+
# inherited_resources assumes the routes are namespaced. If an engine is
|
5
|
+
# mounted at root, however, there will be no namespace.
|
6
|
+
self.resources_configuration[:self][:route_prefix] = nil
|
7
|
+
|
8
|
+
respond_to :html, :json
|
9
|
+
actions :index, :show
|
10
|
+
custom_actions collection: :nested_index, resource: :nested_show
|
11
|
+
|
12
|
+
before_filter :validate_path, only: [:nested_index, :nested_show]
|
13
|
+
|
14
|
+
def index
|
15
|
+
@areas = Area.roots
|
16
|
+
index!
|
17
|
+
end
|
18
|
+
|
19
|
+
def show
|
20
|
+
@area = Area.find_by_slug_or_id(params[:id])
|
21
|
+
show!
|
22
|
+
end
|
23
|
+
|
24
|
+
def nested_index
|
25
|
+
@areas = @area.children
|
26
|
+
|
27
|
+
nested_index! do |format|
|
28
|
+
format.html { render action: 'index'}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def nested_show
|
33
|
+
nested_show! do |format|
|
34
|
+
format.html { render action: 'show'}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
# @raises [Mongoid::Errors::DocumentNotFound] if a resource is improperly nested
|
41
|
+
def validate_path
|
42
|
+
parts = params[:path].split '/'
|
43
|
+
parts.each do |part|
|
44
|
+
@area = Area.find_by(parent_id: @area, slug: part)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Popolo
|
2
|
+
class OrganizationsController < PopoloController
|
3
|
+
inherit_resources
|
4
|
+
# inherited_resources assumes the routes are namespaced. If an engine is
|
5
|
+
# mounted at root, however, there will be no namespace.
|
6
|
+
self.resources_configuration[:self][:route_prefix] = nil
|
7
|
+
|
8
|
+
respond_to :html, :json
|
9
|
+
actions :index, :show
|
10
|
+
custom_actions collection: :nested_index, resource: :nested_show
|
11
|
+
|
12
|
+
before_filter :validate_path, only: [:nested_index, :nested_show]
|
13
|
+
|
14
|
+
def index
|
15
|
+
@organizations = Organization.roots
|
16
|
+
index!
|
17
|
+
end
|
18
|
+
|
19
|
+
def show
|
20
|
+
@organization = Organization.find_by_slug_or_id(params[:id])
|
21
|
+
show!
|
22
|
+
end
|
23
|
+
|
24
|
+
def nested_index
|
25
|
+
@organizations = @organization.children
|
26
|
+
|
27
|
+
nested_index! do |format|
|
28
|
+
format.html { render action: 'index'}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def nested_show
|
33
|
+
nested_show! do |format|
|
34
|
+
format.html { render action: 'show'}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
# @raises [Mongoid::Errors::DocumentNotFound] if a resource is improperly nested
|
41
|
+
def validate_path
|
42
|
+
parts = params[:path].split '/'
|
43
|
+
parts.each do |part|
|
44
|
+
@organization = Organization.find_by(parent_id: @organization, slug: part)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module PopoloHelper
|
2
|
+
# @note inherited_resources sets incorrect arguments for glob routes.
|
3
|
+
# @see https://github.com/josevalim/inherited_resources/blob/master/lib/inherited_resources/url_helpers.rb
|
4
|
+
def nested_resources_path(*args)
|
5
|
+
send("nested_#{resource_collection_name}_path", *args)
|
6
|
+
end
|
7
|
+
def nested_resource_path(*args)
|
8
|
+
send("nested_#{resource_instance_name}_path", *args)
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Popolo
|
2
|
+
# A physical location or a mail delivery point.
|
3
|
+
class Address
|
4
|
+
include Mongoid::Document
|
5
|
+
|
6
|
+
embedded_in :addressable, polymorphic: true
|
7
|
+
|
8
|
+
# The address' type, e.g. 'capitol'.
|
9
|
+
field :type, type: String
|
10
|
+
# The postal address.
|
11
|
+
field :address, type: String
|
12
|
+
# A voice telephone number.
|
13
|
+
field :voice, type: Integer
|
14
|
+
# A facsimile telephone number.
|
15
|
+
field :fax, type: Integer
|
16
|
+
# A mobile telephone number.
|
17
|
+
field :cell, type: Integer
|
18
|
+
# A toll-free telephone number.
|
19
|
+
field :tollfree, type: Integer
|
20
|
+
# A video conferencing telephone number.
|
21
|
+
field :video, type: Integer
|
22
|
+
# A paging device telephone number.
|
23
|
+
field :pager, type: Integer
|
24
|
+
# A telecommunication device for people with hearing or speech difficulties.
|
25
|
+
field :textphone, type: Integer
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Popolo
|
2
|
+
# A bounded area, like an administrative boundary.
|
3
|
+
#
|
4
|
+
# @note There is an upper limit to the number of administrative levels;
|
5
|
+
# however, there is little agreement as to what those levels are. Therefore,
|
6
|
+
# instead of having a different model for each administrative level – which
|
7
|
+
# would have advantages – we use a flexible tree structure.
|
8
|
+
class Area
|
9
|
+
include Mongoid::Document
|
10
|
+
include Mongoid::Tree
|
11
|
+
|
12
|
+
include Popolo::Sluggable
|
13
|
+
index({slug: 1, parent_id: 1}, unique: true)
|
14
|
+
|
15
|
+
# Memberships related to the area, e.g. officials.
|
16
|
+
has_many :memberships, class_name: 'Popolo::Membership'
|
17
|
+
# Organizations related to the area, e.g. governments.
|
18
|
+
has_many :organizations, class_name: 'Popolo::Organization'
|
19
|
+
# Posts related to the area, e.g. officials.
|
20
|
+
has_many :posts, class_name: 'Popolo::Post'
|
21
|
+
|
22
|
+
# The area's category.
|
23
|
+
field :classification, type: String
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Popolo
|
2
|
+
# An occurrence, e.g. an action mentioning or performed by an agent.
|
3
|
+
#
|
4
|
+
# Turtle document: @todo move into popoloproject.com
|
5
|
+
#
|
6
|
+
# <http://example.com/events/57cc67093475061e3d95369d.ttl>
|
7
|
+
# a cnt:ContentAsText;
|
8
|
+
# cnt:characterEncoding "UTF-8";
|
9
|
+
# cnt:chars "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ...";
|
10
|
+
# dcterms:format "text/plain";
|
11
|
+
# dcterms:isFormatOf <http://example.org/news/123.html>;
|
12
|
+
# dcterms:issued "2012-01-01T00:00:00Z"^^xsd:dateTime;
|
13
|
+
# dcterms:identifier "57cc67093475061e3d95369d";
|
14
|
+
# dcterms:created "2012-01-01T00:00:00Z"^^xsd:dateTime;
|
15
|
+
# dcterms:modified "2012-01-01T00:00:00Z"^^xsd:dateTime .
|
16
|
+
#
|
17
|
+
# @see http://www.w3.org/TR/Content-in-RDF10/
|
18
|
+
# @see http://dublincore.org/documents/dcmi-terms/
|
19
|
+
class Event
|
20
|
+
include Mongoid::Document
|
21
|
+
include Mongoid::Timestamps
|
22
|
+
|
23
|
+
# The identifier of the source of information for the event.
|
24
|
+
field :source, type: String
|
25
|
+
# The URL to which the event may be attributed.
|
26
|
+
field :url, type: String
|
27
|
+
# The event's content.
|
28
|
+
field :body, type: String
|
29
|
+
# The time of the event or of its publication.
|
30
|
+
field :issued_at, type: Time
|
31
|
+
# The records related to the event.
|
32
|
+
field :related, type: Hash
|
33
|
+
# Any additional information about the event.
|
34
|
+
field :extra, type: Hash
|
35
|
+
|
36
|
+
# @note It's not possible to do a many-to-many polymorphic relation, so we
|
37
|
+
# must list every index individually.
|
38
|
+
|
39
|
+
index 'related.area' => 1, source: 1, issued_at: -1
|
40
|
+
index 'related.membership' => 1, source: 1, issued_at: -1
|
41
|
+
index 'related.organization' => 1, source: 1, issued_at: -1
|
42
|
+
index 'related.post' => 1, source: 1, issued_at: -1
|
43
|
+
|
44
|
+
validates_presence_of :source, :url, :body, :issued_at
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Popolo
|
2
|
+
# An issued identifier.
|
3
|
+
class Identifier
|
4
|
+
include Mongoid::Document
|
5
|
+
|
6
|
+
embedded_in :organization, class_name: 'Popolo::Organization'
|
7
|
+
|
8
|
+
# An issued identifier, e.g. a DUNS number.
|
9
|
+
field :identifier, type: String
|
10
|
+
# An identifier scheme, e.g. DUNS.
|
11
|
+
field :scheme, type: String
|
12
|
+
|
13
|
+
validates_presence_of :identifier
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Popolo
|
2
|
+
# A URL for a document about a person.
|
3
|
+
class Link
|
4
|
+
include Mongoid::Document
|
5
|
+
|
6
|
+
embedded_in :person, class_name: 'Popolo::Person'
|
7
|
+
|
8
|
+
# A URL for a document about a person.
|
9
|
+
field :url, type: String
|
10
|
+
# A note, e.g. 'Wikipedia page'.
|
11
|
+
field :note, type: String
|
12
|
+
|
13
|
+
validates_presence_of :url
|
14
|
+
# @note Add URL validation to match JSON Schema?
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Popolo
|
2
|
+
# A relationship between a person and an organization.
|
3
|
+
class Membership
|
4
|
+
include Mongoid::Document
|
5
|
+
|
6
|
+
# An area related to the membership, e.g. an electoral riding.
|
7
|
+
belongs_to :area, index: true, class_name: 'Popolo::Area'
|
8
|
+
# The person who is a party to the relationship.
|
9
|
+
belongs_to :organization, index: true, class_name: 'Popolo::Organization'
|
10
|
+
# The organization that is a party to the relationship.
|
11
|
+
belongs_to :person, index: true, class_name: 'Popolo::Person'
|
12
|
+
|
13
|
+
# The role that the person fulfills in the organization. Roles should
|
14
|
+
# preferably belong to a controlled vocabulary.
|
15
|
+
field :role, type: String
|
16
|
+
# The date on which the relationship began.
|
17
|
+
field :start_date, type: String
|
18
|
+
# The date on which the relationship ended.
|
19
|
+
field :end_date, type: String
|
20
|
+
|
21
|
+
validates_presence_of :organization_id, :person_id
|
22
|
+
validates_format_of :start_date, with: /\A\d{4}(-\d{2}){0,2}\z/, allow_blank: true
|
23
|
+
validates_format_of :end_date, with: /\A\d{4}(-\d{2}){0,2}\z/, allow_blank: true
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Popolo
|
2
|
+
# A group with a common purpose or reason for existence that goes beyond the
|
3
|
+
# set of people belonging to it, e.g. a political structure.
|
4
|
+
class Organization
|
5
|
+
include Mongoid::Document
|
6
|
+
include Mongoid::Tree
|
7
|
+
|
8
|
+
include Popolo::Sluggable
|
9
|
+
index({slug: 1, parent_id: 1}, unique: true)
|
10
|
+
|
11
|
+
# An area related to the organization, e.g. a region or country.
|
12
|
+
belongs_to :area, index: true, class_name: 'Popolo::Area'
|
13
|
+
# The relationships to which the organization is a party.
|
14
|
+
has_many :memberships, class_name: 'Popolo::Membership', dependent: :destroy
|
15
|
+
# The posts within the organization.
|
16
|
+
has_many :posts, class_name: 'Popolo::Post', dependent: :destroy
|
17
|
+
# The organization's alternate or former names.
|
18
|
+
embeds_many :other_names, as: :nameable, class_name: 'Popolo::OtherName'
|
19
|
+
# The organization's issued identifiers.
|
20
|
+
embeds_many :identifiers, class_name: 'Popolo::Identifier'
|
21
|
+
|
22
|
+
# The organization's category.
|
23
|
+
field :classification, type: String
|
24
|
+
# The organization's date of founding in ISO 8601:2004 format.
|
25
|
+
field :founding_date, type: String
|
26
|
+
# The organization's date of dissolution in ISO 8601:2004 format.
|
27
|
+
field :dissolution_date, type: String
|
28
|
+
|
29
|
+
validates_format_of :founding_date, with: /\A\d{4}(-\d{2}){0,2}\z/, allow_blank: true
|
30
|
+
validates_format_of :dissolution_date, with: /\A\d{4}(-\d{2}){0,2}\z/, allow_blank: true
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Popolo
|
2
|
+
# An alternate or former name.
|
3
|
+
class OtherName
|
4
|
+
include Mongoid::Document
|
5
|
+
|
6
|
+
embedded_in :nameable, polymorphic: true
|
7
|
+
|
8
|
+
# An alternate or former name.
|
9
|
+
field :name, type: String
|
10
|
+
# The date on which the name was adopted.
|
11
|
+
field :start_date, type: String
|
12
|
+
# The date on which the name was abandoned.
|
13
|
+
field :end_date, type: String
|
14
|
+
# A note, e.g. "Birth name".
|
15
|
+
field :note, type: String
|
16
|
+
|
17
|
+
validates_presence_of :name
|
18
|
+
validates_format_of :start_date, with: /\A\d{4}(-\d{2}){0,2}\z/, allow_blank: true
|
19
|
+
validates_format_of :end_date, with: /\A\d{4}(-\d{2}){0,2}\z/, allow_blank: true
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Popolo
|
2
|
+
# A real person, alive or dead.
|
3
|
+
class Person
|
4
|
+
include Mongoid::Document
|
5
|
+
|
6
|
+
include Popolo::Sluggable
|
7
|
+
index({slug: 1}, unique: true)
|
8
|
+
|
9
|
+
# The relationships to which the person is a party.
|
10
|
+
has_many :memberships, class_name: 'Popolo::Membership'
|
11
|
+
# The posts held by the person.
|
12
|
+
has_many :posts, class_name: 'Popolo::Post'
|
13
|
+
# The person's alternate or former names.
|
14
|
+
embeds_many :other_names, as: :nameable, class_name: 'Popolo::OtherName'
|
15
|
+
# Links to pages about this person, e.g. Wikipedia, or to accounts this
|
16
|
+
# person has on other websites, e.g. Twitter.
|
17
|
+
embeds_many :links, class_name: 'Popolo::Link'
|
18
|
+
|
19
|
+
# The person's family name.
|
20
|
+
field :family_name, type: String
|
21
|
+
# The person's given name.
|
22
|
+
field :given_name, type: String
|
23
|
+
# An additional name, e.g. a middle name.
|
24
|
+
field :additional_name, type: String
|
25
|
+
# An honorific prefix before the person's name, e.g. "Dr.".
|
26
|
+
field :honorific_prefix, type: String
|
27
|
+
# An honorific suffix after the person's name, e.g. "Jr.".
|
28
|
+
field :honorific_suffix, type: String
|
29
|
+
# The person's email address.
|
30
|
+
field :email, type: String
|
31
|
+
# The person's gender, e.g. "male", "female" or another value.
|
32
|
+
field :gender, type: String
|
33
|
+
# The person's date of birth in ISO 8601:2004 format.
|
34
|
+
field :birth_date, type: String
|
35
|
+
# The person's date of death in ISO 8601:2004 format.
|
36
|
+
field :death_date, type: String
|
37
|
+
# The URL of the person's head shot.
|
38
|
+
field :image, type: String
|
39
|
+
# The person's one-line biography.
|
40
|
+
field :summary, type: String
|
41
|
+
# The person's extended biography.
|
42
|
+
field :biography, type: String
|
43
|
+
|
44
|
+
# @note Add email address validation to match JSON Schema?
|
45
|
+
# @note Add URL validation to match JSON Schema?
|
46
|
+
validates_format_of :birth_date, with: /\A\d{4}(-\d{2}){0,2}\z/, allow_blank: true
|
47
|
+
validates_format_of :death_date, with: /\A\d{4}(-\d{2}){0,2}\z/, allow_blank: true
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Popolo
|
2
|
+
# A position in an organization that exists independently of the person
|
3
|
+
# holding it.
|
4
|
+
class Post
|
5
|
+
include Mongoid::Document
|
6
|
+
|
7
|
+
def self.slug_source
|
8
|
+
:role
|
9
|
+
end
|
10
|
+
|
11
|
+
include Popolo::Sluggable
|
12
|
+
index({slug: 1}, unique: true)
|
13
|
+
|
14
|
+
# An area related to the post, e.g. an electoral riding.
|
15
|
+
belongs_to :area, index: true, class_name: 'Popolo::Area'
|
16
|
+
# The organization in which the post exists.
|
17
|
+
belongs_to :organization, index: true, class_name: 'Popolo::Organization'
|
18
|
+
# The person holding the post.
|
19
|
+
belongs_to :person, index: true, class_name: 'Popolo::Person'
|
20
|
+
# The address at which the post is based.
|
21
|
+
embeds_many :addresses, as: :addressable, class_name: 'Popolo::Address'
|
22
|
+
|
23
|
+
validates_presence_of :organization_id
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Popolo
|
2
|
+
# A source of information.
|
3
|
+
#
|
4
|
+
# Turtle document: @todo move into popoloproject.com
|
5
|
+
#
|
6
|
+
# <http://example.com/sources/67cc67093475061e3d95369d.ttl>
|
7
|
+
# rdfs:label "news.google.com";
|
8
|
+
# dcterms:identifier "67cc67093475061e3d95369d";
|
9
|
+
# dcterms:modified "2012-01-01T00:00:00Z"^^xsd:dateTime .
|
10
|
+
#
|
11
|
+
# @see http://dublincore.org/documents/dcmi-terms/
|
12
|
+
# @todo Add the ETag to the Turtle document.
|
13
|
+
class Source
|
14
|
+
include Mongoid::Document
|
15
|
+
|
16
|
+
embedded_in :sourceable, polymorphic: true
|
17
|
+
|
18
|
+
# A human-readable unique identifier for the source, e.g. "news.google.com".
|
19
|
+
field :name, type: String
|
20
|
+
# The source's ETag.
|
21
|
+
field :etag, type: String
|
22
|
+
# The source's last modified timestamp.
|
23
|
+
field :last_modified, type: Time
|
24
|
+
# Any additional information about the source.
|
25
|
+
field :extra, type: Hash
|
26
|
+
|
27
|
+
validates_presence_of :name, :last_modified
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render partial: 'popolo/areas_or_organizations/index', locals: {collection: @areas, object: @area} %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render partial: 'popolo/areas_or_organizations/show', locals: {object: @area} %>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<% if object %>
|
2
|
+
<nav>
|
3
|
+
<ul class="breadcrumb">
|
4
|
+
<li><%= link_to resource_collection_name.capitalize, collection_path %> <span class="divider">/</span></li>
|
5
|
+
<% ancestors = object.ancestors %>
|
6
|
+
<% ancestors.each_with_index do |ancestor,index| %>
|
7
|
+
<li>
|
8
|
+
<%= link_to ancestor.name, nested_resources_path(ancestors[0..index]) %>
|
9
|
+
<span class="divider">/</span>
|
10
|
+
</li>
|
11
|
+
<% end %>
|
12
|
+
<li class="active"><%= object.name %></li>
|
13
|
+
</ul>
|
14
|
+
</nav>
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<% unless collection.empty? %>
|
18
|
+
<% groups = collection.asc(:sort_name).group_by(&:classification) %>
|
19
|
+
<% groups.each do |classification,documents| %>
|
20
|
+
<section>
|
21
|
+
<header>
|
22
|
+
<h1><%= t(classification, scope: [:popolo, resource_collection_name, :classifications]) %></h1>
|
23
|
+
</header>
|
24
|
+
<ul>
|
25
|
+
<% documents.each do |document| %>
|
26
|
+
<li><%= link_to document.name, nested_resources_path([object, document].compact) %></li>
|
27
|
+
<% end %>
|
28
|
+
</ul>
|
29
|
+
</section>
|
30
|
+
<% end %>
|
31
|
+
<% end %>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<nav>
|
2
|
+
<ul class="breadcrumb">
|
3
|
+
<li><%= link_to resource_collection_name.capitalize, collection_path %> <span class="divider">/</span></li>
|
4
|
+
<% ancestors = object.ancestors %>
|
5
|
+
<% ancestors.each_with_index do |ancestor,index| %>
|
6
|
+
<li>
|
7
|
+
<%= link_to ancestor.name, nested_resource_path(ancestors[0..index]) %>
|
8
|
+
<span class="divider">/</span>
|
9
|
+
</li>
|
10
|
+
<% end %>
|
11
|
+
<li class="active"><%= object.name %></li>
|
12
|
+
</ul>
|
13
|
+
</nav>
|
14
|
+
|
15
|
+
<% collection = object.children %>
|
16
|
+
<% unless collection.empty? %>
|
17
|
+
<% groups = collection.asc(:sort_name).group_by(&:classification) %>
|
18
|
+
<% groups.each do |classification,documents| %>
|
19
|
+
<section>
|
20
|
+
<header>
|
21
|
+
<h1><%= t(classification, scope: [:popolo, resource_collection_name, :classifications]) %></h1>
|
22
|
+
</header>
|
23
|
+
<ul>
|
24
|
+
<% documents.each do |document| %>
|
25
|
+
<li><%= link_to document.name, nested_resource_path([object, document]) %></li>
|
26
|
+
<% end %>
|
27
|
+
</ul>
|
28
|
+
</section>
|
29
|
+
<% end %>
|
30
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render partial: 'popolo/areas_or_organizations/index', locals: {collection: @organizations, object: @organization} %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render partial: 'popolo/areas_or_organizations/show', locals: {object: @organization} %>
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|