lib/carte/server.rb
require 'sinatra/base'
require 'sinatra/namespace'
require 'mongoid'
require 'mongoid_auto_increment_id'
require 'will_paginate_mongoid'
require 'mongoid-simple-tags'
require 'mongoid/geospatial'
require 'redcarpet'
require 'carte/server/validators'
require 'carte/server/models'
module Carte
class Server < Sinatra::Base
use Rack::Deflater
register Sinatra::Namespace
include Carte::Server::Models
configure do
set :protection, :except => :path_traversal
set :views, File.join(File.dirname(__FILE__), 'server/views')
set :public_folder, 'public'
set :default, JSON.parse(File.read(File.join(File.dirname(__FILE__), 'shared/default.json')))
set :carte, {}
end
helpers do
def config
@config ||= settings.default.update(settings.carte)
end
def json_data
request.body.rewind
JSON.parse(request.body.read)
end
def search(params)
order = (params[:order] && %w(asc desc random).include?(params[:order])) ? params[:order] : 'desc'
sort = (params[:sort] && %w(title created_at updated_at).include?(params[:sort])) ? params[:sort] : 'updated_at'
if order == 'random'
cards = Card.random
else
cards = Card.send(order, sort)
end
conditions = []
if title = params[:title]
conditions << {title: /#{title}/i}
end
if content = params[:content]
conditions << {content: /#{content}/i}
end
if conditions.size > 0
cards = cards.any_of(conditions)
end
if params[:tags]
tags = params[:tags].split(',')
cards = cards.tagged_with_all(tags)
end
cards = cards.paginate(per_page: 9, page: params[:page])
end
def markdown2html(markdown)
renderer = Redcarpet::Render::HTML.new(filter_html:true)
html = Redcarpet::Markdown.new(renderer, autolink: true).render(markdown)
parse_card_link(html)
end
def parse_card_link(html)
html.gsub(/\[\[(.+?)\]\]/) do |match|
title = $1.dup
if title.match(/<("[^"]*"|'[^']*'|[^'">])*>/)
match
else
%Q(<a href="http://#{request.host}/#/#{URI.escape(title)}">#{title}</a>)
end
end
end
end
get '/cards.xml' do
@cards = search(params)
builder :cards
end
get '/cards.json' do
cards = search(params)
{
cards: cards.map {|card| card.as_json(only: %w(title content tags)).update(version: card.version) },
pagination: {current_page: cards.current_page, total_pages: cards.total_pages, total_entries: cards.total_entries}
}.to_json
end
get '/cards/:title.json' do
context = (params[:context] && %w(title created_at updated_at).include?(params[:context])) ? params[:context] : 'created_at'
card = Card.where(title: params[:title]).first
halt 404 if card.nil?
{
card: card.as_json(only: %w(title content version tags)).update(
version: card.version,
lefts: card.lefts(4, context).as_json(only: %w(title content version tags)),
rights: card.rights(4, context).as_json(only: %w(title content version tags))
)
}.to_json
end
post '/cards.json' do
card = Card.new(json_data.slice('title', 'content', 'tags'))
if card.save
status 201
{}.to_json
else
status 400
{card: {errors: card.errors}}.to_json
end
end
put '/cards/:title.json' do
card = Card.where(title: params[:title]).first
halt 404 if card.nil?
card.histories.create!
if card.update_attributes(json_data.slice('new_title', 'content', 'tags').compact)
status 201
{}.to_json
else
status 400
{card: {errors: card.errors}}.to_json
end
end
#delete '/cards/:title.json' do
# card = Card.where(title: params[:title]).first
# halt 404 if card.nil?
# card.destroy
#end
get '/cards/:title/history.json' do
card = Card.where(title: params[:title]).first
halt 404 if card.nil?
{
history: [
card.as_json(only: %w(title content version tags)).update(version: card.version),
card.histories.desc(:version).as_json(only: %w(title content version tags))
].flatten
}.to_json
end
get '/tags.json' do
{tags: Card.all_tags}.to_json
end
put '/tags/:name.json' do
# TODO: existence and length validation
if json_data['new_name']
cards = Card.collection.where(tags: params[:name])
cards.update(
{'$push' => {tags: json_data['new_name']}},
{:multi => true}
)
cards.update(
{'$pull' => {tags: params[:name]}},
{:multi => true}
)
end
status 201
{}.to_json
end
error(404) do
{}.to_json
end
end
end