apimaster 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +12 -0
- data/apimaster.gemspec +14 -0
- data/bin/apimaster +6 -0
- data/lib/apimaster.rb +21 -0
- data/lib/apimaster/application.rb +28 -0
- data/lib/apimaster/controllers/errors.rb +34 -0
- data/lib/apimaster/error.rb +79 -0
- data/lib/apimaster/generators/application.rb +112 -0
- data/lib/apimaster/generators/base.rb +206 -0
- data/lib/apimaster/generators/command.rb +697 -0
- data/lib/apimaster/generators/manifest.rb +51 -0
- data/lib/apimaster/generators/options.rb +162 -0
- data/lib/apimaster/generators/scripts.rb +64 -0
- data/lib/apimaster/generators/simple_logger.rb +44 -0
- data/lib/apimaster/generators/templates/Gemfile +21 -0
- data/lib/apimaster/generators/templates/LICENSE +20 -0
- data/lib/apimaster/generators/templates/README.md +10 -0
- data/lib/apimaster/generators/templates/Rakefile +19 -0
- data/lib/apimaster/generators/templates/TODO +4 -0
- data/lib/apimaster/generators/templates/app/controllers/index_controller.rb.erb +7 -0
- data/lib/apimaster/generators/templates/config.ru.erb +8 -0
- data/lib/apimaster/generators/templates/config/application.rb.erb +19 -0
- data/lib/apimaster/generators/templates/config/boot.rb.erb +17 -0
- data/lib/apimaster/generators/templates/config/initializer.rb.erb +13 -0
- data/lib/apimaster/generators/templates/config/patches.rb.erb +0 -0
- data/lib/apimaster/generators/templates/config/settings/app.yml.erb +3 -0
- data/lib/apimaster/generators/templates/config/settings/mongoid.yml.erb +66 -0
- data/lib/apimaster/generators/templates/config/settings/oauth.yml.erb +8 -0
- data/lib/apimaster/generators/templates/gitignore +10 -0
- data/lib/apimaster/generators/templates/lib/module.rb.erb +6 -0
- data/lib/apimaster/generators/templates/test/functional_test.rb.erb +2 -0
- data/lib/apimaster/generators/templates/test/test_helper.rb.erb +1 -0
- data/lib/apimaster/generators/templates/test/unit_test.rb.erb +2 -0
- data/lib/apimaster/generators/version.rb +3 -0
- data/lib/apimaster/helpers/headers.rb +30 -0
- data/lib/apimaster/helpers/request.rb +49 -0
- data/lib/apimaster/helpers/session.rb +36 -0
- data/lib/apimaster/mapper.rb +86 -0
- data/lib/apimaster/models/user.rb +33 -0
- data/lib/apimaster/models/user_mock.rb +13 -0
- data/lib/apimaster/setting.rb +68 -0
- metadata +45 -3
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
# Initialize environment
|
3
|
+
ROOT_PATH = File.expand_path(".")
|
4
|
+
ENV["RACK_ENV"] ||= "development"
|
5
|
+
Bundler.require(:default, ENV["RACK_ENV"].to_sym)
|
6
|
+
|
7
|
+
# Initialize settings
|
8
|
+
setting_files = "./config/settings/{app,oauth}.yml"
|
9
|
+
Apimaster::Setting.environment = ENV["RACK_ENV"]
|
10
|
+
Apimaster::Setting.load_file(setting_files)
|
11
|
+
|
12
|
+
# Database setting
|
13
|
+
# Mongoid.load!("./config/settings/mongoid.yml")
|
File without changes
|
@@ -0,0 +1,66 @@
|
|
1
|
+
development:
|
2
|
+
sessions:
|
3
|
+
default:
|
4
|
+
database: mongoid
|
5
|
+
hosts:
|
6
|
+
- localhost:27017
|
7
|
+
|
8
|
+
# Tell Mongoid which environment this configuration is for.
|
9
|
+
production:
|
10
|
+
# This starts the session configuration settings. You may have as
|
11
|
+
# many sessions as you like, but you must have at least 1 named
|
12
|
+
# 'default'.
|
13
|
+
sessions:
|
14
|
+
# Define the default session.
|
15
|
+
default:
|
16
|
+
# A session can have any number of hosts. Usually 1 for a single
|
17
|
+
# server setup, and at least 3 for a replica set. Hosts must be
|
18
|
+
# an array of host:port pairs. This session is single server.
|
19
|
+
hosts:
|
20
|
+
- flame.mongohq.com:27017
|
21
|
+
# Define the default database name.
|
22
|
+
database: mongoid
|
23
|
+
# Since this database points at a session connected to MongoHQ, we must
|
24
|
+
# provide the authentication details.
|
25
|
+
username: user
|
26
|
+
password: password
|
27
|
+
# This defines a secondary session at a replica set.
|
28
|
+
replica_set:
|
29
|
+
# This configuration is a 3 node replica set.
|
30
|
+
hosts:
|
31
|
+
- dedicated1.myapp.com:27017
|
32
|
+
- dedicated2.myapp.com:27017
|
33
|
+
- dedicated3.myapp.com:27017
|
34
|
+
database: mongoid
|
35
|
+
# We can set session specific options, like reads executing
|
36
|
+
# on secondary nodes, and defaulting the session to safe mode.
|
37
|
+
options:
|
38
|
+
consistency: :eventual
|
39
|
+
safe: true
|
40
|
+
# This defines a tertiary session at a Mongos fronted shard.
|
41
|
+
shard:
|
42
|
+
# This configuration is a Mongos shard server.
|
43
|
+
hosts:
|
44
|
+
- mongos.myapp.com:27017
|
45
|
+
database: mongoid
|
46
|
+
# This configuration shows an authenticated replica set via a uri.
|
47
|
+
another:
|
48
|
+
uri: mongodb://user:pass@59.1.22.1:27017,59.1.22.2:27017/mongoid
|
49
|
+
# Here we put the Mongoid specific configuration options. These are explained
|
50
|
+
# in more detail next.
|
51
|
+
options:
|
52
|
+
allow_dynamic_fields: false
|
53
|
+
identity_map_enabled: true
|
54
|
+
include_root_in_json: true
|
55
|
+
include_type_for_serialization: true
|
56
|
+
# Note this can also be true if you want to preload everything, but this is
|
57
|
+
# almost never necessary. Most of the time set this to false.
|
58
|
+
preload_models:
|
59
|
+
- Canvas
|
60
|
+
- Browser
|
61
|
+
- Firefox
|
62
|
+
scope_overwrite_exception: true
|
63
|
+
raise_not_found_error: false
|
64
|
+
skip_version_check: false
|
65
|
+
use_activesupport_time_zone: false
|
66
|
+
use_utc: true
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011-2012 AdMaster, Inc.
|
4
|
+
|
5
|
+
module Apimaster::Helpers
|
6
|
+
module Headers
|
7
|
+
|
8
|
+
def header_pagination(pagination)
|
9
|
+
path = base_url + request.path_info
|
10
|
+
next_link = path + "?" + query_string_modifier(page: pagination.next_page)
|
11
|
+
last_link = path + "?" + query_string_modifier(page: pagination.page_count)
|
12
|
+
pagination_link = "<#{next_link}>; rel=\"next\", <#{last_link}>; rel=\"last\""
|
13
|
+
headers "Link" => pagination_link
|
14
|
+
end
|
15
|
+
|
16
|
+
def header_location(path)
|
17
|
+
headers "Location" => base_url + path
|
18
|
+
end
|
19
|
+
|
20
|
+
def header_link(path, rel)
|
21
|
+
headers "Link" => "<#{base_url+path}>; rel=\"#{rel}\""
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def base_url
|
27
|
+
Apimaster::Setting.get('app.base_url')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011-2012 AdMaster, Inc.
|
4
|
+
#
|
5
|
+
# @author: sunxiqiu@admaster.com.cn
|
6
|
+
|
7
|
+
module Apimaster::Helpers
|
8
|
+
module Request
|
9
|
+
|
10
|
+
# Convert a hash to a querystring for form population
|
11
|
+
def hash_to_query_string(hash)
|
12
|
+
hash.collect {|k,v| "#{k}=#{v}"}.join("&")
|
13
|
+
end
|
14
|
+
|
15
|
+
def query_string_modifier(hash)
|
16
|
+
hash_to_query_string(CGI::parse(request.query_string).merge(hash))
|
17
|
+
end
|
18
|
+
|
19
|
+
def posts
|
20
|
+
@posts ||= to_symbol_key_hash(request_json)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def to_symbol_key_hash(hash)
|
26
|
+
return hash unless hash.is_a? Hash
|
27
|
+
result = {}
|
28
|
+
hash.map do |key, val|
|
29
|
+
val = to_symbol_key_hash(val) if val.is_a? Hash
|
30
|
+
result[key.to_sym] = val
|
31
|
+
end
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
def request_json
|
36
|
+
begin
|
37
|
+
@request_json ||= parse_json
|
38
|
+
rescue JSON::ParserError => e
|
39
|
+
raise Apimaster::RequestError, "Problems parsing JSON"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_json
|
44
|
+
body_data = request.body.read
|
45
|
+
body_data.empty? ? {} : JSON.parse(body_data)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011-2012 AdMaster, Inc.
|
4
|
+
#
|
5
|
+
# @author: sunxiqiu@admaster.com.cn
|
6
|
+
|
7
|
+
module Apimaster::Helpers
|
8
|
+
module Session
|
9
|
+
|
10
|
+
# Check logged in user is the owner
|
11
|
+
def is_owner? owner_id
|
12
|
+
!!current_user && current_user.id.to_i == owner_id.to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def authorize
|
16
|
+
raise Apimaster::UnauthorizedError.new :user unless current_user
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return current_user record if logged in
|
20
|
+
def current_user
|
21
|
+
@current_user ||= auth_user
|
22
|
+
end
|
23
|
+
|
24
|
+
def auth_user
|
25
|
+
@access_token ||= params[:access_token] or header_token
|
26
|
+
(test? ? Apimaster::Models::UserMock : Apimaster::Models::User).auth @access_token
|
27
|
+
end
|
28
|
+
|
29
|
+
def header_token
|
30
|
+
keys = %w{HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION}
|
31
|
+
authorization ||= keys.inject(nil) { |auth, key| auth || request.env[key] }
|
32
|
+
authorization.split[1] if authorization and authorization[/^token/i]
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011-2012 AdMaster, Inc.
|
4
|
+
|
5
|
+
module Apimaster
|
6
|
+
class Mapper
|
7
|
+
# include Mongoid::Document
|
8
|
+
|
9
|
+
def post hash
|
10
|
+
from_hash hash
|
11
|
+
save
|
12
|
+
end
|
13
|
+
|
14
|
+
def put hash
|
15
|
+
from_hash hash
|
16
|
+
save
|
17
|
+
end
|
18
|
+
|
19
|
+
def patch hash
|
20
|
+
from_hash hash
|
21
|
+
save
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_hash accessor = :all
|
25
|
+
record = {}
|
26
|
+
fields = self.class.find_attrs_in_options(:accessor, accessor)
|
27
|
+
fields.each do |field|
|
28
|
+
if self.respond_to?(field)
|
29
|
+
record[field] = self.send(field)
|
30
|
+
else
|
31
|
+
raise "Dataset #{self.class} has no method with the name of #{field}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
record
|
35
|
+
end
|
36
|
+
|
37
|
+
def from_hash(hash, method = :all)
|
38
|
+
data = {}
|
39
|
+
attrs = [:required, :optional]
|
40
|
+
|
41
|
+
attrs.each do |type|
|
42
|
+
fields = self.class.get_attrs(type, method)
|
43
|
+
fields.each do |field|
|
44
|
+
if hash.has_key?(field)
|
45
|
+
data[field] = hash[field]
|
46
|
+
elsif hash.has_key?(field.to_s)
|
47
|
+
data[field] = hash[field.to_s]
|
48
|
+
else
|
49
|
+
raise Apimaster::MissingFieldError.new(self.class.get_class_name, field) if type == :required
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
data.each do |key, val|
|
55
|
+
respond_setter key, val
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def respond_setter key, val
|
60
|
+
name = (key.to_s + '=').to_sym
|
61
|
+
raise "#{self.class} lost of #{name}" unless self.respond_to?(name)
|
62
|
+
self.send name, val
|
63
|
+
end
|
64
|
+
|
65
|
+
class << self
|
66
|
+
|
67
|
+
OPTION_TYPES = [:accessor, :required, :optional]
|
68
|
+
|
69
|
+
@attr_options ||= {}
|
70
|
+
|
71
|
+
# attr_options :url, accessor: [:get, :list]
|
72
|
+
def attr_options name, options = {}
|
73
|
+
@attr_options[name] = options
|
74
|
+
end
|
75
|
+
|
76
|
+
# [:url, :name]
|
77
|
+
def find_attrs_in_options type, option = :all
|
78
|
+
raise "Unknown attribute options type: #{type}" unless OPTION_TYPES.include? type
|
79
|
+
@attr_options.select do |name, options|
|
80
|
+
type_options = options.is_a?(Hash) and options.key?(type) ? options[type] : nil
|
81
|
+
type_options.is_a?(Array) and (type_options.include?(option) or type_options.include(:all))
|
82
|
+
end.keys
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011-2012 AdMaster, Inc.
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
module Apimaster::Models
|
8
|
+
class User
|
9
|
+
|
10
|
+
attr_accessor :id
|
11
|
+
attr_accessor :email
|
12
|
+
attr_accessor :username
|
13
|
+
|
14
|
+
def initialize hash
|
15
|
+
hash.each do |key, val|
|
16
|
+
method_name = (key.to_s+'=').to_sym
|
17
|
+
self.send(method_name, val) if respond_to?(method_name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.auth access_token
|
22
|
+
oauth_domain = Apimaster::Setting.get('oauth.oauth_domain')
|
23
|
+
json = Net::HTTP.get(oauth_domain, "/user?access_token=#{access_token}", 80)
|
24
|
+
user_hash = JSON.parse(json)
|
25
|
+
|
26
|
+
return nil unless user_hash.is_a?(Hash)
|
27
|
+
raise Apimaster::OauthError.new(user_hash["message"]) if user_hash.key?("message")
|
28
|
+
|
29
|
+
self.new user_hash
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011-2012 AdMaster, Inc.
|
4
|
+
|
5
|
+
module Apimaster
|
6
|
+
|
7
|
+
module Setting
|
8
|
+
class << self
|
9
|
+
@@hashes = {}
|
10
|
+
|
11
|
+
# environments: development, test and production.
|
12
|
+
ENVIRONMENTS = %w[test production development]
|
13
|
+
|
14
|
+
attr_accessor :environment
|
15
|
+
|
16
|
+
def set(key, value)
|
17
|
+
@@hashes[key] = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(key, default = nil)
|
21
|
+
current = @@hashes
|
22
|
+
key.split('.').each do |k|
|
23
|
+
if current and current.is_a?(Hash)
|
24
|
+
current = current.has_key?(k) ? current[k] : default
|
25
|
+
end
|
26
|
+
end
|
27
|
+
current
|
28
|
+
end
|
29
|
+
|
30
|
+
# Loads the configuration from the YAML files whose +paths+ are passed as
|
31
|
+
# arguments, filtering the settings for the current environment. Note that
|
32
|
+
# these +paths+ can actually be globs.
|
33
|
+
def load_file(*paths)
|
34
|
+
paths.each do |pattern|
|
35
|
+
Dir.glob(pattern) do |file|
|
36
|
+
yaml = config_for_env(YAML.load_file(file)) || {}
|
37
|
+
yaml.each_pair do |key, value|
|
38
|
+
for_env = config_for_env(value)
|
39
|
+
set key, for_env unless value and for_env.nil? and respond_to? key
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Given a +hash+ with some application configuration it returns the
|
48
|
+
# settings applicable to the current environment. Note that this can only
|
49
|
+
# be done when all the keys of +hash+ are environment names included in the
|
50
|
+
# +environments+ setting (which is an Array of Strings). Also, the
|
51
|
+
# returned config is a indifferently accessible Hash, which means that you
|
52
|
+
# can get its values using Strings or Symbols as keys.
|
53
|
+
def config_for_env(hash)
|
54
|
+
if hash.respond_to? :keys and hash.keys.all? { |k| ENVIRONMENTS.include? k.to_s }
|
55
|
+
hash = hash[environment.to_s] || hash[environment.to_sym]
|
56
|
+
end
|
57
|
+
|
58
|
+
if hash.respond_to? :to_hash
|
59
|
+
indifferent_hash = Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
|
60
|
+
indifferent_hash.merge hash.to_hash
|
61
|
+
else
|
62
|
+
hash
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|