- 1 Etherpad-lite ruby library
- 2 Crabgrass code changes
- 2.1 Files changed/added
- 2.2 DB tables added
- 2.3 Comments to the code
- 2.3.1 config/locales/en/pages.yml
- 2.3.2 extensions/pages/pad_page/app/controllers/pad_page_controller.rb
- 2.3.3 extensions/pages/pad_page/app/views/pad_page/show.html.erb
- 2.3.4 test/functional/pad_page_controller_test.rb
- 2.4 Example trace
- 2.5 Example of js if we’d like to use the jquery lib
- 3 Works
- 4 To fix
- 5 To check
- 6 To do
Adding a new Page type called Pad that has as data an etherpad iframe
See how to install etherpad-lite install etherpad-lite
Etherpad-lite ruby library¶
Using github.com/jhollinger/ruby-etherpad-lite library
Install it “gem install etherpad-lite”
HTTP-API¶
Data Types
groupID a string, the unique id of a group. Format is g.16RANDOMCHARS, for example g.s8oes9dhwrvt0zif
sessionID a string, the unique id of a session. Format is s.16RANDOMCHARS, for example s.s8oes9dhwrvt0zif
authorID a string, the unique id of an author. Format is a.16RANDOMCHARS, for example a.s8oes9dhwrvt0zif
readOnlyID a string, the unique id of an readonly relation to a pad. Format is r.16RANDOMCHARS, for example r.s8oes9dhwrvt0zif
padID a string, format is GROUPID$PADNAME, for example the pad test of group g.s8oes9dhwrvt0zif has padID g.s8oes9dhwrvt0zif$test
Only users with a valid session for this group, can access group pads
You should save the sessionID of this session and delete it after the user logged out
Hands Ruby-etherpad-lite¶
ruby script/console
require 'etherpad-lite'
ether = EtherpadLite.connect('http://localhost:9001', '7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO')
ether = EtherpadLite.connect(:local, File.new('/var/www/etherpad-lite/APIKEY.txt'))
pad = ether.pad('my first etherpad lite pad')=> #<EtherpadLite::Pad:0xb5f009dc @id="my first etherpad lite pad"
# Map your app's group to an EtherpadLite Group
# equivalent to /api/1/createGroupIfNotExistsFor?groupMapper=2000&apikey=...
group = ether.group("my_app_group_#{@app_group.id}")
#author = ether.group(id, name)
# Get the EtherpadLite Group and Pad by id
@group = ether.get_group(params[:group_id])
# Get or create an hour-long session for this Author in this Group
sess = session[:ep_sessions][@group.id] ? ether.get_session(session[:ep_sessions][@group.id]) : @group.create_session(author, 60)
if sess.expired?
sess.delete
sess = @group.create_session(author, 60)
end
session[:ep_sessions][@group.id] = sess.id
# Set the EtherpadLite session cookie. This will automatically be picked up by the jQuery plugin's iframe.
cookies[:sessionID] = {:value => sess.id, :domain => ".yourdomain.com"}
Example requests and responses¶
Extracted from from /var/log/etherpad-lite.log
API - REQUEST, createAuthorIfNotExistsFor, {"apikey":"7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO","authorMapper":"4","name":"blue"}
API - RESPONSE, createAuthorIfNotExistsFor, {"code":0,"message":"ok","data":{"authorID":"a.0uTNv4QGzEDdniaI"}}
http - 200, GET /api/1/createAuthorIfNotExistsFor?apikey=7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO&authorMapper=4&name=blue
#epg = ep.group(2000)
API - REQUEST, createGroupIfNotExistsFor, {"groupMapper":"2000","apikey":"7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO"}
API - RESPONSE, createGroupIfNotExistsFor, {"code":0,"message":"ok","data":{"groupID":"g.x4rEQoMdP2K85LWc"}}
http - 200, GET /api/1/createGroupIfNotExistsFor?groupMapper=2000&apikey=7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO
API - REQUEST, createGroupPad, {"apikey":"7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO","groupID":"g.x4rEQoMdP2K85LWc","padName":"mypad"}
API - RESPONSE, createGroupPad, {"code":0,"message":"ok","data":{"padID":"g.x4rEQoMdP2K85LWc$mypad"}}
http - 200, GET /api/1/createGroupPad?apikey=7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO&groupID=g.x4rEQoMdP2K85LWc&padName=mypad
API - REQUEST, createSession, {"validUntil":"1337259943","apikey":"7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO","groupID":"g.x4rEQoMdP2K85LWc","authorID":"a.0uTNv4QGzEDdniaI"}
API - RESPONSE, createSession, {"code":0,"message":"ok","data":{"sessionID":"s.PaZ4JYSUcldgk5JB"}}
http - 200, GET /api/1/createSession?validUntil=1337259943&apikey=7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO&groupID=g.x4rEQoMdP2K85LWc&authorID=a.0uTNv4QGzEDdniaI
# socket.io - handshake authorized '1958083917176744501'
# message - from 1958083917176744501: {"component":"pad","type":"CLIENT_READY","padId":"g.x4rEQoMdP2K85LWc$mypad","sessionID":"s.NA5y8KIxGYOXG5jc","password":null,"token":"t.nGKY8MXC0Y6gHQmtlx5Y","protocolVersion":2}
API - REQUEST, getSessionInfo, {"apikey":"7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO","sessionID":"s.PaZ4JYSUcldgk5JB"}
API - RESPONSE, getSessionInfo, {"code":0,"message":"ok","data":{"groupID":"g.x4rEQoMdP2K85LWc","authorID":"a.0uTNv4QGzEDdniaI","validUntil":1337259943}}
http - 200, GET /api/1/getSessionInfo?apikey=7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO&sessionID=s.PaZ4JYSUcldgk5JB
API - REQUEST, deleteSession, {"apikey":"7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO","sessionID":"s.PaZ4JYSUcldgk5JB"}
API - RESPONSE, deleteSession, {"code":0,"message":"ok","data":null}
http - 200, GET /api/1/deleteSession?apikey=7DU3LJWh7pGojsniRAtnqFi7ayzPy4fO&sessionID=s.PaZ4JYSUcldgk5JB
Crabgrass code changes¶
The branch where the code is: github.com/janaya/Crabgrass-Core/tree/e...
Most of the code created lives on extensions/pages/pad_page
Files changed/added¶
config/locales/en/pages.yml
config/crabgrass/crabgrass.development.yml # Add PadPage here, still needed?
app/models/observers/page_observer.rb
config/initializers/etherpad-lite.rb
extensions/pages/pad_page/init.rb
extensions/pages/pad_page/lib/EPL.rb
extensions/pages/pad_page/app/models/pad.rb
extensions/pages/pad_page/app/models/pad_page.rb
extensions/pages/pad_page/app/controllers/pad_page_controller.rb
extensions/pages/pad_page/app/views/pad_page/show.html.erb
extensions/pages/pad_page/app/helpers/pad_page_helper.rb
extensions/pages/pad_page/test/functional/pad_page_controller_test.rb
extensions/pages/pad_page/test/unit/EPL_test.rb
extensions/pages/pad_page/test/unit/pad_page_test.rb
db/migrate/20120517105001_create_pads.rb
db/schema.rb
DB tables added¶
Pad¶
# create_table do |t|
# t.integer :page_id
# t.string :name
# t.blob :text
# t.string :url
# end
create_table "pads", :force => true do |t|
t.string "name"
t.string "url"
t.text "text"
t.integer "revision", :default => 0
t.integer "page_id"
t.datetime "created_at"
t.datetime "updated_at"
end
Comments to the code¶
config/locales/en/pages.yml¶
PadPage here, still needed?
config/crabgrass/crabgrass.development.yml
pad_page_description: "Create a collaborative editor for a group."
pad_page_display: "Pad"
extensions/pages/pad_page/app/controllers/pad_page_controller.rb¶
etherpad needs the cookie, otherwise u get permission denied
ep session is in session cookie, cg session is in session
just ensure that if ep_sessions was not in the global rails session variable, add it
def refresh_epl_session
session[:ep_sessions] ||= {}
extensions/pages/pad_page/app/views/pad_page/show.html.erb¶
it creates a frame with the etherpad url
test/functional/pad_page_controller_test.rb¶
for tests, the symbol needs to be wroten as string
cookies['sessionID']
Example trace¶
extensions/pages/pad_page/app/models/pad.rb:22:in `create_pad_on_etherpad'
extensions/pages/pad_page/app/models/pad.rb:40:in `sync'
extensions/pages/pad_page/app/models/pad.rb:40:in `new'
extensions/pages/pad_page/lib/EPL.rb:27:in `initialize'
extensions/pages/pad_page/lib/EPL.rb:94:in `create_pad!'
Example of js if we’d like to use the jquery lib¶
<script src="js/etherpad.js"></script>
<div id="examplePadBasic"></div>
<script type="text/javascript">
// A slightly more intense example
$('#examplePadIntense').pad({'padId':'test2','showChat':'true'}); // sets the pad id and puts the pad in the div
</script>
Works¶
- Creating a pad as user is created with group anyway
- Sharing a pad with other user works
- Granting access to one pad of a group does not grant access to other pads.
To fix¶
- Sharing a pad with another user in readonly mode still allow the other user to write
- Add a pad_page icon different from the page_icon
- Pad renaming (not only the Page but change also the name of the pad)
To check¶
- When is etherpad showing the message reconnecting?
- If a group shares a pad with another group, will the next pad be shared too by default?
- changing ownership of a pad (e.g., from a user to the group) should recreate the pad under the group. (move)
- of course, the original pad should be deleted then, but does that affect history?
- → changing ownership does not (yet) move the pad, so it’s a failing case
- How to move the history?
To do¶
- Rename sess to ep_session, user, group, etc to don’t confuse ep stuff with cg one
- DONE: group_mapping is configurable per container, and should be chosen to be a unique string.
(was: Add owner type as in @page.owner_id, the user id and group id might be the same) - DONE page title should not be editable, or the pad should be recreated with the right contents
- DONE tests are missing!
- CLOSED some edge cases with etherpad-lite not loading the pad (etherpad-lite issue)—didn’t happen in a while
- some page functionalities should be disabled?
- DONE without the sessionID cookie, one cannot access the pad: if the session entry exists,
but not the cookie, it should be created. - destroying the page should remove the pad
- for a static view, contents should be fetched from
page.pad.text -> maybe =
page.data= would cache the latest revision when a static view is requested - WONTFIX Editing the page title should rename the pad (but that would break the URL) → the title is set once for all by hashing the original title.
- edit : current iframe with editor
- show: text without the editor/colors…
- print: like show but without all cg menus and so on