mumuki-bibliotheca 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 20ad4ce643d71a35210b3a5147bb148fa9db30fc
4
+ data.tar.gz: d6cf6ab9a0a1ef05070e6a62cc3be0cef7a656b8
5
+ SHA512:
6
+ metadata.gz: 945fdcd017255e86ea50565ffa29cef07393f628365048804cf259e299d1dc4107d8e9899512f2851ddeef56b5d42263b6932da9c78cf26dd5cef55e3ddb9ec0
7
+ data.tar.gz: 2b75fdbd6b1952a77009a19b894450366eccacf9ba70afbb347fa6912e963bda1c15a7331df00ef62288cdb7c8e2bd47c0a83e7cde26f1cea6e160e9cf03fcde
data/README.md ADDED
@@ -0,0 +1,141 @@
1
+ [![Build Status](https://travis-ci.org/mumuki/mumuki-bibliotheca-api.svg?branch=master)](https://travis-ci.org/mumuki/mumuki-bibliotheca-api)
2
+ [![Code Climate](https://codeclimate.com/github/mumuki/mumuki-bibliotheca-api/badges/gpa.svg)](https://codeclimate.com/github/mumuki/mumuki-bibliotheca-api)
3
+ [![Test Coverage](https://codeclimate.com/github/mumuki/mumuki-bibliotheca-api/badges/coverage.svg)](https://codeclimate.com/github/mumuki/mumuki-bibliotheca-api)
4
+ [![Issue Count](https://codeclimate.com/github/mumuki/mumuki-bibliotheca-api/badges/issue_count.svg)](https://codeclimate.com/github/mumuki/mumuki-bibliotheca-api)
5
+
6
+ # Mumuki Bibliotheca API
7
+ > Storage and formatting API for guides
8
+
9
+ ## About
10
+
11
+ Bibliotheca is a service for storing Mumuki content - Books, Topics and Guides. Its main persistent media is MongoDB, but it is also capable of importing and exporting guides from a Github repository. Features:
12
+
13
+ * REST API
14
+ * Importing and exporting to a Github repository
15
+ * Listing and upserting guides in JSON format
16
+ * Pemissions validation
17
+ * Optional changes notifications to Aheneum
18
+
19
+ ## Preparing environment
20
+
21
+ ### 1. Install essentials and base libraries
22
+
23
+ > First, we need to install some software: MongoDB and some common Ruby on Rails native dependencies
24
+
25
+ 1. Follow [MongoDB installation guide](https://docs.mongodb.com/v3.2/tutorial/install-mongodb-on-ubuntu/)
26
+ 2. Run:
27
+
28
+ ```bash
29
+ sudo apt-get install autoconf curl git build-essential libssl-dev autoconf bison libreadline6 libreadline6-dev zlib1g zlib1g-dev
30
+ ```
31
+
32
+ ### 2. Install rbenv
33
+
34
+ > [rbenv](https://github.com/rbenv/rbenv) is a ruby versions manager, similar to rvm, nvm, and so on.
35
+
36
+ ```bash
37
+ curl https://raw.githubusercontent.com/rbenv/rbenv-installer/master/bin/rbenv-installer | bash
38
+ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc # or .bash_profile
39
+ echo 'eval "$(rbenv init -)"' >> ~/.bashrc # or .bash_profile
40
+ ```
41
+
42
+ ### 3. Install ruby
43
+
44
+ > Now we have rbenv installed, we can install ruby and [bundler](http://bundler.io/)
45
+
46
+ ```bash
47
+ rbenv install 2.3.1
48
+ rbenv global 2.3.1
49
+ rbenv rehash
50
+ gem install bundler
51
+ gem install escualo
52
+ ```
53
+
54
+ ### 4. Clone this repository
55
+
56
+ > Because, err... we need to clone this repostory before developing it :stuck_out_tongue:
57
+
58
+ ```bash
59
+ git clone https://github.com/mumuki/mumuki-bibliotheca-api bibliotheca-api
60
+ cd bibliotheca-api
61
+ ```
62
+
63
+ ## Installing and Running
64
+
65
+ ### Quick start
66
+
67
+ If you want to start the server quickly in developer environment,
68
+ you can just do the following:
69
+
70
+ ```bash
71
+ ./devstart
72
+ ```
73
+
74
+ This will install your dependencies and boot the server.
75
+
76
+ ### Installing the server
77
+
78
+ If you just want to install dependencies, just do:
79
+
80
+ ```
81
+ bundle install
82
+ ```
83
+
84
+ ### Running the server
85
+
86
+ You can boot the server by using the standard rackup command:
87
+
88
+ ```
89
+ # using defaults from config/puma.rb and rackup default port 9292
90
+ bundle exec rackup
91
+
92
+ # changing port
93
+ bundle exec rackup -p 8080
94
+
95
+ # changing threads count
96
+ MUMUKI_BIBLIOTHECA_API_THREADS=30 bundle exec rackup
97
+ ```
98
+
99
+ Or you can also start it with `puma` command, which gives you more control:
100
+
101
+ ```
102
+ # using defaults from config/puma.rb
103
+ bundle exec puma
104
+
105
+ # changing ports and threads count, using puma-specific options:
106
+ bundle exec puma -t 2:30 -p 8080
107
+
108
+ # changing ports and threads count, using environment variables:
109
+ MUMUKI_BIBLIOTHECA_API_PORT=8080 MUMUKI_BIBLIOTHECA_API_THREADS=30 bundle exec puma
110
+ ```
111
+
112
+ ## Running tests
113
+
114
+ ```bash
115
+ bundle exec rspec
116
+ ```
117
+
118
+ ## Running tasks
119
+
120
+ ```bash
121
+ # import guides from a github organization
122
+ bundle exec rake guides:import[<a github organization>]
123
+
124
+ # import languages from http://thesaurus.mumuki.io
125
+ bundle exec rake languages:import
126
+ ```
127
+
128
+ ## Running Migrations
129
+
130
+ ```bash
131
+ # migration_name is the name of the migration file in ./migrations/, without extension and the "migrate_" prefix
132
+ bundle exec rake db:migrate[<migration_name>]
133
+ ```
134
+
135
+ ## See also
136
+
137
+ [Bibliotheca Web Client](https://github.com/mumuki/mumuki-bibliotheca)
138
+
139
+ ## Authentication Powered by Auth0
140
+
141
+ <a width="150" height="50" href="https://auth0.com/" target="_blank" alt="Single Sign On & Token Based Authentication - Auth0"><img width="150" height="50" alt="JWT Auth for open source projects" src="http://cdn.auth0.com/oss/badges/a0-badge-dark.png"/></a>
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Mumuki::Bibliotheca'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+ load 'rails/tasks/statistics.rake'
20
+
21
+ require 'bundler/gem_tasks'
22
+
23
+ require 'rspec/core'
24
+ require 'rspec/core/rake_task'
25
+
26
+ desc "Run all specs in spec directory (excluding plugin specs)"
27
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
28
+
29
+ task default: :spec
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
data/lib/events.rb ADDED
@@ -0,0 +1,15 @@
1
+ Mumukit::Nuntius::EventConsumer.handle do
2
+ # Emitted by:
3
+ # * new logins in laboratory
4
+ # * new logins in classroom
5
+ # * user creation and modification in laboratory
6
+ # * user creation and modification in classroom
7
+ event :UserChanged do |data|
8
+ User.import_from_resource_h! payload.deep_symbolize_keys[:user]
9
+ end
10
+
11
+ # Emitted by organization creation and modification in laboratory
12
+ event :OrganizationChanged do |payload|
13
+ Organization.import_from_resource_h! payload.deep_symbolize_keys[:organization]
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ module Mumuki
2
+ module Bibliotheca
3
+ end
4
+ end
5
+
6
+ require 'mumuki/domain'
7
+ require 'mumukit/login'
8
+ require 'mumukit/nuntius'
9
+ require 'mumukit/platform'
10
+
11
+ Mumukit::Nuntius.configure do |c|
12
+ c.app_name = 'bibliotheca'
13
+ end
14
+
15
+ Mumukit::Platform.configure do |config|
16
+ config.application = Mumukit::Platform.bibliotheca_api
17
+ config.web_framework = Mumukit::Platform::WebFramework::Sinatra
18
+ end
19
+
20
+ require_relative './bibliotheca/syncer'
21
+ require_relative './bibliotheca/sinatra'
22
+ require_relative './bibliotheca/engine'
@@ -0,0 +1,8 @@
1
+ module Mumuki
2
+ module Bibliotheca
3
+ class Engine < ::Rails::Engine
4
+ endpoint Sinatra::Application.new
5
+ config.generators.api_only = true
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,176 @@
1
+ require 'sinatra'
2
+ require 'mumukit/content_type'
3
+
4
+ require 'sinatra/cross_origin'
5
+ require 'logger'
6
+ require 'mumukit/auth'
7
+
8
+ require 'json'
9
+ require 'yaml'
10
+
11
+ configure do
12
+ enable :cross_origin
13
+ set :allow_methods, [:get, :put, :post, :options, :delete]
14
+ set :show_exceptions, false
15
+
16
+ set :app_name, 'bibliotheca'
17
+ set :static, true
18
+ set :public_folder, 'public'
19
+
20
+ use ::Rack::CommonLogger, Rails.logger
21
+ end
22
+
23
+ helpers do
24
+ def json_body
25
+ @json_body ||= JSON.parse(request.body.read) rescue nil
26
+ end
27
+
28
+ def slug
29
+ if route_slug_parts.present?
30
+ Mumukit::Auth::Slug.join(*route_slug_parts)
31
+ elsif subject
32
+ Mumukit::Auth::Slug.parse(subject.slug)
33
+ elsif json_body
34
+ Mumukit::Auth::Slug.parse(json_body['slug'])
35
+ else
36
+ raise Mumukit::Auth::InvalidSlugFormatError.new('Slug not available')
37
+ end
38
+ end
39
+
40
+ def route_slug_parts
41
+ []
42
+ end
43
+ end
44
+
45
+ before do
46
+ content_type 'application/json', 'charset' => 'utf-8'
47
+ end
48
+
49
+ after do
50
+ error_message = env['sinatra.error']
51
+ if response.body.is_a?(Array)&& response.body[0].is_a?(String)
52
+ if content_type != 'application/csv'
53
+ content_type 'text/html'
54
+ response.body[0] = <<HTML
55
+ <html>
56
+ <body>
57
+ #{response.body[0]}
58
+ </body>
59
+ </html>
60
+ HTML
61
+ end
62
+ response.body = response.body[0]
63
+ elsif error_message.blank?
64
+ response.body = response.body.to_json
65
+ else
66
+ response.body = {message: env['sinatra.error'].message}.to_json
67
+ end
68
+ end
69
+
70
+ error JSON::ParserError do
71
+ halt 400
72
+ end
73
+
74
+ error Mumukit::Auth::InvalidTokenError do
75
+ halt 401
76
+ end
77
+
78
+ error Mumukit::Auth::UnauthorizedAccessError do
79
+ halt 403
80
+ end
81
+
82
+ error ActiveRecord::RecordInvalid do
83
+ halt 400
84
+ end
85
+
86
+ error Mumukit::Auth::InvalidSlugFormatError do
87
+ halt 400
88
+ end
89
+
90
+ error ActiveRecord::RecordNotFound do
91
+ halt 404
92
+ end
93
+
94
+ options '*' do
95
+ response.headers['Allow'] = settings.allow_methods.map { |it| it.to_s.upcase }.join(',')
96
+ response.headers['Access-Control-Allow-Headers'] = 'X-Mumuki-Auth-Token, X-Requested-With, X-HTTP-Method-Override, Content-Type, Cache-Control, Accept, Authorization'
97
+ 200
98
+ end
99
+
100
+ helpers do
101
+ Mumukit::Login.configure_controller! self
102
+ end
103
+
104
+ before do
105
+ I18n.locale = 'en' #TODO: Remove hardcoded locale
106
+ end
107
+
108
+ helpers do
109
+ def authenticate!
110
+ halt 401 unless current_user?
111
+ end
112
+
113
+ def authorization_slug
114
+ slug
115
+ end
116
+
117
+ def subject
118
+ Guide.find_by_id(params[:id])
119
+ end
120
+
121
+ def route_slug_parts
122
+ [params[:organization], params[:repository]].compact
123
+ end
124
+
125
+ def history_syncer
126
+ Mumuki::Bibliotheca.history_syncer(current_user)
127
+ end
128
+
129
+ def api_syncer
130
+ Mumuki::Bibliotheca.api_syncer(json_body)
131
+ end
132
+
133
+ def upsert!(content_kind)
134
+ authorize! :writer
135
+ content = api_syncer.locate_and_import! content_kind, slug.to_s
136
+ history_syncer.export! content
137
+ content.to_resource_h
138
+ end
139
+
140
+ def fork!(collection_class)
141
+ authorize! :writer
142
+ destination = json_body['organization']
143
+ collection_class.find_by_slug!(slug.to_s).fork_to!(destination, history_syncer).as_json
144
+ end
145
+
146
+ def delete!(collection_class)
147
+ authorize! :editor
148
+ collection_class.find_by_slug!(slug.to_s).destroy!
149
+ {}
150
+ end
151
+ end
152
+
153
+ post '/markdown' do
154
+ {markdown: Mumukit::ContentType::Markdown.to_html(json_body['markdown'])}
155
+ end
156
+
157
+ post '/markdowns' do
158
+ json_body.with_indifferent_access.tap do |guide|
159
+ guide[:exercises].each do |exercise|
160
+ exercise[:description] = Mumukit::ContentType::Markdown.to_html(exercise[:description])
161
+ end
162
+ end
163
+ end
164
+
165
+ get '/permissions' do
166
+ authenticate!
167
+
168
+ {permissions: current_user.permissions}
169
+ end
170
+
171
+
172
+ require_relative './sinatra/organization'
173
+ require_relative './sinatra/languages'
174
+ require_relative './sinatra/guides'
175
+ require_relative './sinatra/books'
176
+ require_relative './sinatra/topics'
@@ -0,0 +1,29 @@
1
+ helpers do
2
+ def list_books(books)
3
+ { books: books.as_json(only: [:name, :slug, :chapters]) }
4
+ end
5
+ end
6
+
7
+ get '/books' do
8
+ list_books Book.all
9
+ end
10
+
11
+ get '/books/writable' do
12
+ list_books Book.allowed(current_user.permissions)
13
+ end
14
+
15
+ get '/books/:organization/:repository' do
16
+ Book.find_by_slug!(slug.to_s).to_resource_h
17
+ end
18
+
19
+ post '/books' do
20
+ upsert! :book
21
+ end
22
+
23
+ post '/book/:organization/:repository/fork' do
24
+ fork! Book
25
+ end
26
+
27
+ delete '/books/:organization/:repository' do
28
+ delete! Book
29
+ end
@@ -0,0 +1,45 @@
1
+ helpers do
2
+ def list_guides(guides)
3
+ { guides: guides.map { |it| it.as_json(only: [:name, :slug, :type]).merge(language: it.language.name) } }
4
+ end
5
+
6
+ def slice_guide_resource_h_for_api(guide)
7
+ guide.merge(language: guide.dig(:language, :name)).merge(exercises: guide[:exercises].map { |it| it.tap { |it| it[:language] = it.dig(:language, :name) if it[:language]}})
8
+ end
9
+ end
10
+
11
+ get '/guides' do
12
+ list_guides Guide.visible(current_user&.permissions)
13
+ end
14
+
15
+ get '/guides/writable' do
16
+ list_guides Guide.allowed(current_user&.permissions)
17
+ end
18
+
19
+ delete '/guides/:organization/:repository' do
20
+ delete! Guide
21
+ end
22
+
23
+ get '/guides/:organization/:repository/markdown' do
24
+ slice_guide_resource_h_for_api Guide.find_by_slug!(slug.to_s).to_markdownified_resource_h
25
+ end
26
+
27
+ get '/guides/:organization/:repository' do
28
+ slice_guide_resource_h_for_api Guide.find_by_slug!(slug.to_s).to_resource_h
29
+ end
30
+
31
+ post '/guides' do
32
+ upsert! :guide
33
+ end
34
+
35
+ post '/guides/import/:organization/:repository' do
36
+ history_syncer.locate_and_import! :guide, slug.to_s
37
+ end
38
+
39
+ post '/guides/:organization/:repository/assets' do
40
+ Mumuki::Bibliotheca.upload_asset! slug, json_body['filename'], json_body['content']
41
+ end
42
+
43
+ post '/guides/:organization/:repository/fork' do
44
+ fork! Guide
45
+ end
@@ -0,0 +1,10 @@
1
+ get '/languages' do
2
+ { languages: Language.all.map { |it| transform(it) } }
3
+ end
4
+
5
+ def transform(language)
6
+ language
7
+ .to_resource_h
8
+ .replace_key!(:highlight_mode, :ace_mode)
9
+ .replace_key!(:runner_url, :test_runner_url)
10
+ end
@@ -0,0 +1,3 @@
1
+ get '/organization' do
2
+ Organization.base.to_resource_h
3
+ end
@@ -0,0 +1,29 @@
1
+ helpers do
2
+ def list_topics(topics)
3
+ { topics: topics.as_json(only: [:name, :slug]) }
4
+ end
5
+ end
6
+
7
+ get '/topics' do
8
+ list_topics Topic.all
9
+ end
10
+
11
+ get '/topics/writable' do
12
+ list_topics Topic.allowed(current_user.permissions)
13
+ end
14
+
15
+ get '/topics/:organization/:repository' do
16
+ Topic.find_by_slug!(slug.to_s).to_resource_h
17
+ end
18
+
19
+ post '/topics' do
20
+ upsert! :topic
21
+ end
22
+
23
+ post '/book/:organization/:repository/fork' do
24
+ fork! Topic
25
+ end
26
+
27
+ delete '/topics/:organization/:repository' do
28
+ delete! Topic
29
+ end
@@ -0,0 +1,29 @@
1
+ module Mumuki
2
+ module Bibliotheca
3
+ class ApiSource < Mumukit::Sync::Store::Json
4
+ include Mumukit::Sync::Store::WithWrappedLanguage
5
+ include Mumukit::Sync::Store::WithFilteredId
6
+ end
7
+
8
+ class << self
9
+ class_attribute :api_inflators, :history_inflators, :history_store, :assets_uploader
10
+
11
+ self.api_inflators = [Mumukit::Sync::Inflator::SingleChoice.new, Mumukit::Sync::Inflator::MultipleChoice.new]
12
+ self.history_inflators = []
13
+ self.history_store = proc { |_user| Mumukit::Sync::Store::NullStore.new }
14
+ self.assets_uploader = proc { |_slug, _name, _content| raise 'Can not upload file' }
15
+
16
+ def upload_asset!(slug, name, content)
17
+ assets_uploader[slug, name, content]
18
+ end
19
+
20
+ def history_syncer(user)
21
+ Mumukit::Sync::Syncer.new(history_store[user], history_inflators)
22
+ end
23
+
24
+ def api_syncer(json)
25
+ Mumukit::Sync::Syncer.new(ApiSource.new(json), api_inflators)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ module Mumuki
2
+ module Bibliotheca
3
+ VERSION = '6.0.0'
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ namespace :content do
2
+ task :import do
3
+ bridge = Mumukit::Platform.bibliotheca_bridge
4
+ bridge.import_contents! do |resource_type, slug|
5
+ resource = bridge.send(resource_type, slug)
6
+
7
+ Bibliotheca::Collection.insert_hash! resource_type, resource
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ logger = Mumukit::Nuntius::Logger
2
+ namespace :events do
3
+ task :listen do
4
+ logger.info 'Loading event handlers....'
5
+ require_relative '../events'
6
+ logger.info "Loaded handlers #{Mumukit::Nuntius::EventConsumer.handled_events}!"
7
+
8
+ logger.info 'Listening to events...'
9
+ Mumukit::Nuntius::EventConsumer.start!
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+ namespace :guides do
2
+ def guides_for_organization(org)
3
+ Octokit.auto_paginate = true
4
+ Octokit.repos(org).map(&:full_name).select { |it| it =~ /guia/ }
5
+ end
6
+
7
+ task :export, [:author_email] do |_t, args|
8
+ author_email = args[:author_email]
9
+ Bibliotheca::Collection::Guides.all.each do |it|
10
+ it.export! author_email rescue (puts "ignoring #{it.slug}")
11
+ end
12
+ end
13
+
14
+ task :import_from_github, [:organization, :url] do |_t, args|
15
+ args.with_defaults(url: 'http://localhost:3004')
16
+
17
+ org = args[:organization]
18
+ url = args[:url]
19
+
20
+ puts "importing guides from organization #{org} into #{url}"
21
+
22
+ guides_for_organization(org).each do |slug|
23
+ puts "importing guide #{slug}...."
24
+ begin
25
+ RestClient.post "#{url}/guides/import/#{slug}", {}
26
+ rescue => e
27
+ puts "import failed! #{e.response}"
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+
34
+
35
+
36
+
metadata ADDED
@@ -0,0 +1,187 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mumuki-bibliotheca
3
+ version: !ruby/object:Gem::Version
4
+ version: 6.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Franco Bulgarelli
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: sinatra-contrib
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sinatra-cross_origin
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.3.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.3.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: mumuki-domain
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 6.0.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 6.0.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: mumukit-login
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '6.1'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '6.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mumukit-nuntius
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '6.1'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '6.1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: mumukit-sync
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.2'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.2'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rack
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pg
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.18.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.18.0
139
+ description: API for editing content on mumuki
140
+ email:
141
+ - franco@mumuki.org
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - README.md
147
+ - Rakefile
148
+ - config/routes.rb
149
+ - lib/events.rb
150
+ - lib/mumuki/bibliotheca.rb
151
+ - lib/mumuki/bibliotheca/engine.rb
152
+ - lib/mumuki/bibliotheca/sinatra.rb
153
+ - lib/mumuki/bibliotheca/sinatra/books.rb
154
+ - lib/mumuki/bibliotheca/sinatra/guides.rb
155
+ - lib/mumuki/bibliotheca/sinatra/languages.rb
156
+ - lib/mumuki/bibliotheca/sinatra/organization.rb
157
+ - lib/mumuki/bibliotheca/sinatra/topics.rb
158
+ - lib/mumuki/bibliotheca/syncer.rb
159
+ - lib/mumuki/bibliotheca/version.rb
160
+ - lib/tasks/content.rake
161
+ - lib/tasks/events.rake
162
+ - lib/tasks/guides.rake
163
+ homepage: https://mumuki.org
164
+ licenses:
165
+ - GPL-3.0
166
+ metadata: {}
167
+ post_install_message:
168
+ rdoc_options: []
169
+ require_paths:
170
+ - lib
171
+ required_ruby_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ required_rubygems_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ requirements: []
182
+ rubyforge_project:
183
+ rubygems_version: 2.5.1
184
+ signing_key:
185
+ specification_version: 4
186
+ summary: API for editing content on mumuki
187
+ test_files: []