Digital Social Innovation
Released under the MIT-LICENSE.
Setup
The app is pretty much a standard Rails app, except that it uses Tripod and MongoDB instead of ActiveRecord.
All public data is stored in a Fuseki triple store, and accessed via the ORM-like Tripod API.
All private data is stored in MongoDB.
This repository no longer contains any configuration values, so for
example to get it running you will need to copy the
development_example.rb
file to development.rb
and adjust the
settings for your configuration.
Like wise when deploying to production you will need to ensure some configuration files are copied up to the server. The capistrano setup task will do this, but you will need to ensure that at setup time the files are available locally. Some example files are provided for these production services, these are:
config/s3.example.yml
which is used for image uploads.config/development_example.rb
standard rails development environment.config/production_example.rb
standard rails production environment.config/test_example.rb
standard rails test environment.config/mongoid.yml.example
example mongoid config.config/raven_production_example.rb
config initializer for mandril SMTP.config/secret_token_production_example.rb
config initializer to secure cookies with a salt.
Production
To deploy to production you will need to generate a random secret_token.
$ irb
1.9.3-p448 :001 > require 'securerandom'
=> true
1.9.3-p448 :002 > SecureRandom.hex(64)
=> "0677f2adfd6d181fd5d6abf4d047f526f57db7355705ab97624b08024622c94cf72d8e3a9469667df69feb916af4bab4dcefcecd7e0d103025ad92b007676acc"
Then copy the random string into the secret_token, and copy this file to config/initializers/secret_token_production.rb .
The capistrano setup task willl then copy this to the server in the shared/ directory within the app.
Setting up Fuseki
Here is an example fuseki configuration:
@prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
@prefix fuseki: <http://jena.apache.org/fuseki#> .
[] rdf:type fuseki:Server ;
# Services available. Only explicitly listed services are configured.
# If there is a service description not linked from this list, it is ignored.
fuseki:services (
<#digitalsocial_dev>
<#digitalsocial_reporting>
<#digitalsocial_test>
) .
# add more services here ^^
[] ja:loadClass "com.hp.hpl.jena.tdb.TDB" .
tdb:DatasetTDB rdfs:subClassOf ja:RDFDataset .
tdb:GraphTDB rdfs:subClassOf ja:Model .
<#junk_data> rdf:type tdb:DatasetTDB ;
tdb:location "/tmp/digitalsocial_dev_data" ; # change to suit your local installation
# Query timeout on this dataset (1s, 1000 milliseconds)
ja:context [ ja:cxtName "arq:queryTimeout" ; ja:cxtValue "10000,10000" ] ;
tdb:unionDefaultGraph true ;
.
<#digitalsocial_dev> rdf:type fuseki:Service ;
fuseki:name "digitalsocial_dev" ; # http://host:port/myname
fuseki:serviceQuery "sparql" ; # SPARQL query service http://host:port/odc/sparql?query=...
fuseki:serviceUpdate "update" ; # SPARQL update servicehttp://host:port/odc/update?query=
fuseki:serviceReadWriteGraphStore "data" ; # SPARQL Graph store protocol (read and write)
fuseki:dataset <#digitalsocial_dev_data> ;
.
<#digitalsocial_dev_data> rdf:type tdb:DatasetTDB ;
tdb:location "/tmp/digitalsocial_dev_data" ; # change to suit your local installation
# Query timeout on this dataset (1s, 1000 milliseconds)
ja:context [ ja:cxtName "arq:queryTimeout" ; ja:cxtValue "10000,10000" ] ;
tdb:unionDefaultGraph true ;
.
<#digitalsocial_test_data> rdf:type tdb:DatasetTDB ;
tdb:location "/tmp/digitalsocial_test_data" ; # change to suit your local installation
# Query timeout on this dataset (1s, 1000 milliseconds)
ja:context [ ja:cxtName "arq:queryTimeout" ; ja:cxtValue "10000,10000" ] ;
tdb:unionDefaultGraph true ;
.
Editing reminder emails
To change the email content, edit the files in app/views/request_mailer
.
The table below summarises all the emails that are sent out:
| File (.text.erb
) | Purpose | When |
| ------------- |------------- | -----|---|
| organisation_invite
| To notify a user that they have been invited to join an organisation. | Immediately |
| project_new_organisation_invite
| To notify a user that does not already exist in the system that they have been invited to join a project. | Immediately |
| project_request_acceptance
| To notify all users of an organisation that their invitation to a project was accepted. | Immediately |
| projectless_user_reminder
| To remind all users of organisations without at least 1 project that they should add one. | Cron (Every Tuesday at 10:30am)
| request_digest
| To remind all users with any pending items, a summary of those items. | Cron (Every Tuesday at 10:15am) |
| unconfirmed_user_reminder
| To remind an unconfirmed user to log in (i.e. someone who has been invited but is yet to log in for the first time and set their password). | Cron (Every Tuesday at 10:30am). |
| user_request_acceptance
| To notify a user that their request to join an organisation was accepted. | Immediately |
Downloading a list of users
To download a CSV of existing users, visit /admin/users.csv
. You must be logged in as an Admin
.
This path will provide a CSV containing the users' first name, email address, and list of their organisations.
For example:
Ric,ric@swirrl.com,Swirrl
Bill,bill@swirrl.com,Swirrl
John,john.smith@megacorp.com,Megacorp
To change the fields of this CSV, edit the User.to_csv
method in the User
model.
Making survey questions compulsory/optional
About you (Step 1)
The User
is created on this step. first_name
, email
and password
are all required here. These validations can be found in the User
model. It is strongly recommended you do not remove these.
View for this step can be found at app/views/organisations/build/new_user.html.haml
.
Org Basics (Step 2)
This step initializes a new OrganisationPresenter
(found in app/presenters
).
The presenter then creates the Organisation
, Site
and Address
records from the submitted form. Edit the presence validation in this presenter to require the appropriate fields in the form.
View for this step can be found at app/views/organisations/build/new_organisation.html.haml
.
Org details (Step 3)
This step edits an existing Organisation
. Add validations to the Organisation
model.
Note that any validations added here will also be applied to Step 2. To avoid this, ensure that it only applies to a persisted record.
E.g. in app/models/user.rb
validates :twitter_username, presence: true, unless: :new_record?
View for this step can be found at app/views/organisations/build/edit_organisation.html.haml
.
1st project (Step 4)
This step creates a new Project
.
Add any validations for these fields in app/models/project.rb
.
View for this step can be found at app/views/organisations/build/new_project.html.haml
.
Project details (Step 5)
This step updates the Project
created in the previous step. Any validations applied for this step must have the unless :first_step?
clause. This ensures that any validations applied here do not prevent Step 4 from progressing.
View for this step can be found at app/views/organisation/build/edit_project.html.haml
.
Project invites (Step 6)
This step initializes a new ProjectInvitePresenter
(found in app/presenters
).
The presenter then creates the ProjectInvite
and, if they do not already exist, a new User
and Organisation
. Edit the presence validation in this presenter to require the appropriate fields in the form.
View for this step can be found at app/views/organisations/build/invite_organisations.html.haml
.
Making fields appear required
If an if
or unless
clause has been applied to a validation, SimpleForm will not automatically make the field appear required.
To resolve this, add required: true
to the appropriate field in the view.
Accessing the underlying data using SPARQL
The data on organisations and associated projects can be retrieved by SPARQL queries. Here is a selection of example queries that might help you get started with retrieving data. These can be tested via the SPARQL console. For full details of the available options for SPARQL and other APIs, see the Developer Documentation.
Organisations
A list of organisations
SELECT ?org WHERE {?org a <http://www.w3.org/ns/org#Organization>}
A list of the properties associated with an organisation
SELECT DISTINCT ?prop WHERE
{?org a <http://www.w3.org/ns/org#Organization> .
?org ?prop ?o}
A list of organisations and values of their properties
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX dsi: <http://data.digitalsocial.eu/def/ontology/>
PREFIX org: <http://www.w3.org/ns/org#>
SELECT ?org ?label ?webpage ?numstaff ?twitter ?orgtype ?logo_url ?site WHERE
{?org a <http://www.w3.org/ns/org#Organization> ;
rdfs:label ?label .
OPTIONAL { ?org foaf:page ?webpage }
OPTIONAL { ?org dsi:numberOfFTEStaff ?numstaff }
OPTIONAL { ?org dsi:twitterAccount ?twitter }
OPTIONAL { ?org dsi:organizationType ?orgtype}
OPTIONAL { ?org foaf:logo ?logo_url }
OPTIONAL { ?org org:hasPrimarySite ?site }
}
The address and location information for an organisation is associated with the value of the org:hasPrimarySite property.
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX org: <http://www.w3.org/ns/org#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?label ?lat ?long WHERE {
?org a org:Organization ;
org:hasPrimarySite ?site ;
rdfs:label ?label .
?site geo:lat ?lat ;
geo:long ?long .
}
Connecting organisations and activities
Organisations are connected to projects (or 'activities') via an 'ActivityMembership' resource.
All ActivityMembership resources:
PREFIX dsi: <http://data.digitalsocial.eu/def/ontology/>
SELECT * WHERE {?org_act a dsi:ActivityMembership}
As well as connecting an organisation and an activity, the ActivityMembership describes the type of role that the organisation played in the activity.
PREFIX dsi: <http://data.digitalsocial.eu/def/ontology/>
SELECT ?org ?activity ?role WHERE {
?org_act a dsi:ActivityMembership ;
dsi:organization ?org ;
dsi:activity ?activity ;
dsi:role ?role
}
Activities
A list of the properties associated with an activity.
PREFIX dsi: <http://data.digitalsocial.eu/def/ontology/>
SELECT DISTINCT ?prop WHERE
{?activity a dsi:Activity .
?activity ?prop ?o}
A list of all activities and the organisations involved in them.
PREFIX dsi: <http://data.digitalsocial.eu/def/ontology/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT ?activity ?organisation WHERE {
?org_act dsi:organization ?org .
?org_act dsi:activity ?act .
?org rdfs:label ?organisation .
?act rdfs:label ?activity } ORDER BY ?activity
A list of activities with their associated properties.
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX dsi: <http://data.digitalsocial.eu/def/ontology/>
PREFIX org: <http://www.w3.org/ns/org#>
PREFIX dct: <http://purl.org/dc/terms/>
SELECT ?activity ?label ?webpage ?description ?organisation ?activity_type
?area_of_society ?tech_focus ?tech_method ?innovation_area ?social_impact WHERE
{?activity a dsi:Activity .
?activity rdfs:label ?label .
OPTIONAL { ?activity ?page ?webpage }
OPTIONAL { ?activity dct:description ?description }
OPTIONAL { ?activity dsi:recordedBy ?organisation }
OPTIONAL { ?activity dsi:activityType ?activity_type }
OPTIONAL { ?activity dsi:areaOfSociety ?area_of_society}
OPTIONAL { ?activity dsi:technologyFocus ?tech_focus }
OPTIONAL { ?activity dsi:technologyMethod ?tech_method }
OPTIONAL { ?activity dsi:areaOfDigitalSocialInnovation ?innovation_area }
OPTIONAL { ?activity dsi:socialImpact ?social_impact }
}