ppc 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +37 -0
  3. data/.rspec +2 -0
  4. data/LICENSE +339 -0
  5. data/README.md +78 -0
  6. data/lib/ppc.rb +17 -0
  7. data/lib/ppc/api.rb +10 -0
  8. data/lib/ppc/api/baidu.rb +138 -0
  9. data/lib/ppc/api/baidu/account.rb +47 -0
  10. data/lib/ppc/api/baidu/bulk.rb +41 -0
  11. data/lib/ppc/api/baidu/creative.rb +125 -0
  12. data/lib/ppc/api/baidu/group.rb +111 -0
  13. data/lib/ppc/api/baidu/keyword.rb +204 -0
  14. data/lib/ppc/api/baidu/plan.rb +68 -0
  15. data/lib/ppc/api/baidu/report.rb +143 -0
  16. data/lib/ppc/api/qihu.rb +107 -0
  17. data/lib/ppc/api/qihu/account.rb +86 -0
  18. data/lib/ppc/api/qihu/creative.rb +106 -0
  19. data/lib/ppc/api/qihu/group.rb +113 -0
  20. data/lib/ppc/api/qihu/keyword.rb +111 -0
  21. data/lib/ppc/api/qihu/plan.rb +64 -0
  22. data/lib/ppc/api/qihu/report.rb +159 -0
  23. data/lib/ppc/api/shenma.rb +64 -0
  24. data/lib/ppc/api/shenma/report.rb +135 -0
  25. data/lib/ppc/api/sogou.rb +122 -0
  26. data/lib/ppc/api/sogou/account.rb +42 -0
  27. data/lib/ppc/api/sogou/creative.rb +117 -0
  28. data/lib/ppc/api/sogou/group.rb +116 -0
  29. data/lib/ppc/api/sogou/keyword.rb +182 -0
  30. data/lib/ppc/api/sogou/plan.rb +66 -0
  31. data/lib/ppc/api/sogou/report.rb +129 -0
  32. data/lib/ppc/ext.rb +9 -0
  33. data/lib/ppc/operation.rb +196 -0
  34. data/lib/ppc/operation/account.rb +53 -0
  35. data/lib/ppc/operation/creative.rb +28 -0
  36. data/lib/ppc/operation/group.rb +59 -0
  37. data/lib/ppc/operation/keyword.rb +32 -0
  38. data/lib/ppc/operation/plan.rb +47 -0
  39. data/lib/ppc/operation/report.rb +19 -0
  40. data/ppc.gemspec +26 -0
  41. data/spec/baidu/api_baidu_account_spec.rb +15 -0
  42. data/spec/baidu/api_baidu_creative_spec.rb +67 -0
  43. data/spec/baidu/api_baidu_group_spec.rb +45 -0
  44. data/spec/baidu/api_baidu_keyword_spec.rb +61 -0
  45. data/spec/baidu/api_baidu_plan_spec.rb +43 -0
  46. data/spec/baidu/api_baidu_report_spec.rb +44 -0
  47. data/spec/baidu/api_baidu_spec.rb +55 -0
  48. data/spec/operation/operation_baidu_report_spec.rb +17 -0
  49. data/spec/operation/operation_baidu_spec.rb +78 -0
  50. data/spec/operation/operation_qihu_report_spec.rb +18 -0
  51. data/spec/operation/operation_qihu_spec.rb +51 -0
  52. data/spec/operation/operation_sogou_report_spec.rb +17 -0
  53. data/spec/operation/operation_sogou_spec.rb +51 -0
  54. data/spec/operation/operation_spec_helper.rb +51 -0
  55. data/spec/qihu/api_qihu_account_spec.rb +25 -0
  56. data/spec/qihu/api_qihu_creative_spec.rb +48 -0
  57. data/spec/qihu/api_qihu_group_spec.rb +40 -0
  58. data/spec/qihu/api_qihu_keyword_spec.rb +50 -0
  59. data/spec/qihu/api_qihu_plan_spec.rb +39 -0
  60. data/spec/qihu/api_qihu_report_spec.rb +54 -0
  61. data/spec/sogou/api_sogou_account_spec.rb +15 -0
  62. data/spec/sogou/api_sogou_creative_spec.rb +48 -0
  63. data/spec/sogou/api_sogou_group_spec.rb +45 -0
  64. data/spec/sogou/api_sogou_keyword_spec.rb +50 -0
  65. data/spec/sogou/api_sogou_plan_spec.rb +39 -0
  66. data/spec/sogou/api_sogou_report_spec.rb +51 -0
  67. data/spec/spec_helper.rb +134 -0
  68. metadata +177 -0
@@ -0,0 +1,86 @@
1
+ # -*- coding:utf-8 -*-
2
+ require 'json'
3
+ module PPC
4
+ module API
5
+ class Qihu
6
+ class Account < Qihu
7
+ Service = 'account'
8
+
9
+ @map = [
10
+ [ :id, :uid ],
11
+ [ :name, :userName ],
12
+ [ :email, :email],
13
+ [ :company, :companyName],
14
+ [ :industry1, :industry1],
15
+ [ :industry2, :industry2],
16
+ [ :balance, :balance],
17
+ [ :budget, :budget],
18
+ [ :resources, :resources],
19
+ [ :open_domains, :allowDomain]
20
+ ]
21
+
22
+ def self.info( auth )
23
+ response = request( auth, Service, 'getInfo' )
24
+ process( response, '' ){ |x| reverse_type( x )[0]}
25
+ end
26
+
27
+ def self.update( auth, params )
28
+ '''
29
+ 对奇虎两个update的在封装。如果所有操作成功,succ为true,否则为false
30
+ failure中以字符串方式返回失败的操作
31
+ '''
32
+ result = {}
33
+ result[:succ] = true
34
+ result[:failure] = []
35
+ result[:result] = []
36
+
37
+ if params[:budget] != nil
38
+ budget_result = update_budget( auth, params[:budget] )
39
+ result[:succ] = result[:succ] && budget_result[:succ]
40
+ result[:failure] << 'budget' unless budget_result[:succ]
41
+ end
42
+
43
+ if params[:exclude_ip] != nil
44
+ ip_result = update_exclude_ip( auth, params[:exclude_ip] )
45
+ result[:succ] = result[:succ] && ip_result[:succ]
46
+ result[:failure] << 'exclude_ip' unless budget_result[:succ]
47
+ end
48
+
49
+ return result
50
+ end
51
+
52
+ def self.get_all_object( auth, ids )
53
+ #文档上面写的输入类型是String?
54
+ body = { 'idList' => ids }
55
+ response = request( auth, Service, 'getAllObjects' )
56
+ process( response, 'account_getAllObjects_response' ){ |x| x }
57
+ end
58
+
59
+ def self.get_file_state( auth, id )
60
+ body = { 'fileId' => id }
61
+ response = request( auth, Service, 'getAllObjects' , body )
62
+ process( response, 'account_getFileState_response' ){ |x| x }
63
+ end
64
+
65
+ def self.get_exclude_ip( auth )
66
+ response = request( auth, Service, 'getExcludeIp' )
67
+ process( response, 'excludeIpList' ){ |x| x['item'] }
68
+ end
69
+
70
+ private
71
+ def self.update_budget( auth, budget )
72
+ response = request( auth, Service, 'updateBudget', { budget:budget })
73
+ process( response, 'affectedRecords' ){ | x | x.to_i==1?'success':'failure' }
74
+ end
75
+
76
+ private
77
+ def self.update_exclude_ip( auth, ips )
78
+ ips = to_json_string( ips )
79
+ response = request( auth, Service, 'updateExcludeIp', { excludeIpList: ips } )
80
+ process( response, 'excludeIpList' ){ | x | x }
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,106 @@
1
+ # -*- coding:utf-8 -*-
2
+ module PPC
3
+ module API
4
+ class Qihu
5
+ class Creative< Qihu
6
+ Service = 'creative'
7
+
8
+ @map = [
9
+ [:id,:id] ,
10
+ [:group_id, :groupId],
11
+ [:title,:title],
12
+ [:description1, :description1],
13
+ [:description2, :description2],
14
+ [:pc_destination, :destinationUrl],
15
+ [:pc_display, :displayUrl]
16
+ ]
17
+
18
+ @status_map = [
19
+ [:id,:id],
20
+ [:quality,:qualityScore],
21
+ [:status,:status]
22
+ ]
23
+
24
+ def self.get( auth, ids )
25
+ body = { 'idList' => to_json_string( ids ) }
26
+ response = request( auth, Service, 'getInfoByIdList', body )
27
+ process( response, 'creativeList'){ |x| reverse_type( x['item'] ) }
28
+ end
29
+
30
+ def self.add( auth, creatives )
31
+ creative_types = make_type( creatives ).to_json
32
+ body = { 'creatives' => creative_types}
33
+ response = request( auth, Service, 'add', body )
34
+ process( response, 'creativeIdList'){ |x| to_id_hash_list( x['item'] ) }
35
+ end
36
+
37
+ # helper function for self.add() method
38
+ private
39
+ def self.to_id_hash_list( str )
40
+ reuturn [] if str == nil
41
+ str = [str] unless str.is_a?Array
42
+ x= []
43
+ str.each{ |i| x << { id: i.to_i } }
44
+ return x
45
+ end
46
+
47
+ def self.update( auth, creatives )
48
+ creative_types = make_type( creatives ).to_json
49
+ body = { 'creatives' => creative_types}
50
+ response = request( auth, Service, 'update', body )
51
+ process( response, 'affectedRecords', 'failCreativeIds' ){ |x| x }
52
+ end
53
+
54
+ # 对update的再封装实现activate方法,未测试
55
+ def self.activate( auth, ids )
56
+ creatives = []
57
+ ids.each{ |id| creatives << { id: id, status:'enable'} }
58
+ update( auth, creatives )
59
+ end
60
+
61
+ def self.delete( auth, ids )
62
+ ids = to_json_string( ids )
63
+ body = { 'idList' => ids }
64
+ response = request( auth, Service, 'deleteByIdList', body )
65
+ process( response, 'affectedRecords' ){ |x|x }
66
+ end
67
+
68
+ def self.status( auth, ids )
69
+ body = { idList: to_json_string( ids ) }
70
+ response = request( auth, Service, 'getStatusByIdList', body )
71
+ process( response, 'creativeList' ){ |x| reverse_type( x['item'], @status_map ) }
72
+ end
73
+
74
+ # quality 本质上和 status 在一个方法里面
75
+ def self.quality( auth, ids )
76
+ status( auth, ids)
77
+ end
78
+
79
+ def self.search_id_by_group_id( auth, id, status = nil)
80
+ # 处理条件
81
+ body = {}
82
+ body['status'] = status if status
83
+ body['groupId'] = id
84
+ response = request( auth, Service, 'getIdListByGroupId', body )
85
+ # 伪装成百度接口
86
+ process( response, 'creativeIdList' ){
87
+ |x|
88
+ [ { group_id:id, creative_ids:to_id_list( x==nil ? nil: x['item'] ) } ]
89
+ }
90
+ end
91
+
92
+ # combine two methods to provide another mether
93
+ def self.search_by_group_id( auth, id )
94
+ creative_ids = search_id_by_group_id( auth, id )
95
+ response = get( auth , creative_ids )
96
+ # 伪装成百度接口
97
+ if response[:succ]
98
+ response[:result] = [ { group_id:id, creatives:response[:result ] } ]
99
+ end
100
+ return response
101
+ end
102
+
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,113 @@
1
+ # -*- coding:utf-8 -*-
2
+ module PPC
3
+ module API
4
+ class Qihu
5
+ class Group < Qihu
6
+ Service = 'group'
7
+
8
+ @map = [
9
+ [:id, :id ],
10
+ [:plan_id, :campaignId],
11
+ [:status, :status ],
12
+ [:name, :name ],
13
+ [:price, :price ],
14
+ # negateive为json格式,make_type要定制
15
+ [:negative, :negativeWords ],
16
+ [:add_time, :addTime],
17
+ [:update_time, :updateTime]
18
+ ]
19
+
20
+ # 再次封装提供all和ids
21
+ def self.ids( auth )
22
+ '''
23
+ 接口与其他的相同,但是无论如何:succ均为true,不返回任何错误信息
24
+ 因为是重复调用了search的接口,速度非常的慢,* 慎用 *
25
+ '''
26
+ plan_ids = ::PPC::API::Qihu::Plan::ids( auth )[:result]
27
+ plan_group_ids = []
28
+
29
+ plan_ids.each do |plan_id|
30
+ plan_group_id = {}
31
+ plan_group_id[:plan_id] = plan_id
32
+ plan_group_id[:group_ids] = search_id_by_plan_id( auth, plan_id )[:result]
33
+ plan_group_ids << plan_group_id
34
+ end
35
+ return { succ: true, failure:nil, result: plan_group_ids }
36
+ end
37
+
38
+ def self.all( auth )
39
+ '''
40
+ unimplemented due to ineffciency
41
+ '''
42
+ # unimplement
43
+ end
44
+
45
+ # 奇虎组服务不提供批量add,delete和update方法
46
+ def self.add( auth, group )
47
+ response = request( auth, Service, 'add', make_type( group )[0] )
48
+ # 保证接口一致性
49
+ process( response, 'id' ){ |x| [ { id:x.to_i } ] }
50
+ end
51
+
52
+ def self.update( auth, group )
53
+ response = request( auth, Service, 'update', make_type( group )[0] )
54
+ # 保证接口一致性
55
+ process( response, 'id' ){ |x|[ { id:x.to_i } ] }
56
+ end
57
+
58
+ def self.get( auth, ids )
59
+ ids = to_json_string( ids )
60
+ body = { 'idList' => ids }
61
+ response = request( auth, Service, 'getInfoByIdList', body )
62
+ process( response, 'groupList' ){ |x| reverse_type( x['item'] ) }
63
+ end
64
+
65
+ def self.delete( auth, id )
66
+ response = request( auth, Service, 'deleteById', { id: id} )
67
+ process( response, 'affectedRecords' ){ |x| x == '1' }
68
+ end
69
+
70
+ def self.search_id_by_plan_id( auth, id )
71
+ response = request( auth, Service, 'getIdListByCampaignId', { 'campaignId' => id.to_s })
72
+ #为了保持接口一致性,这里也是伪装成了百度的接口
73
+ process( response, 'groupIdList' ){
74
+ |x|
75
+ [ { plan_id:id, group_ids: to_id_list( x==nil ? nil: x['item'] ) } ]
76
+ }
77
+ end
78
+
79
+ # combine searchIdbyId and get to provide another method
80
+ def self.search_by_plan_id( auth, id )
81
+ group_ids = search_id_by_plan_id( auth, id )[:result][0][:group_ids]
82
+ response = get( auth, group_ids )
83
+ if response[:succ]
84
+ response[:result] = [ { plan_id:id, groups:response[:result]}]
85
+ end
86
+ return response
87
+ end
88
+
89
+ # customize make type to convert negative word
90
+ def self.make_type( params, map = @map)
91
+ '''
92
+ '''
93
+ params = [ params ] unless params.is_a? Array
94
+
95
+ types = []
96
+ params.each do |param|
97
+ type = {}
98
+
99
+ map.each do |key|
100
+ # next line transfer negative param to json
101
+ key[0]==:negative&&param[:negative] ? value=param[:negative].to_json : value=param[key[0]]
102
+ type[ key[1] ] = value if value != nil
103
+ end
104
+
105
+ types << type
106
+ end
107
+ return types
108
+ end
109
+
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,111 @@
1
+ # -*- coding:utf-8 -*-
2
+ module PPC
3
+ module API
4
+ class Qihu
5
+ class Keyword< Qihu
6
+ Service = 'keyword'
7
+
8
+ @map = [
9
+ [:id, :id],
10
+ [:group_id, :groupId],
11
+ [:keyword, :word],
12
+ [:price, :price],
13
+ [:match_type, :matchType],
14
+ [:pc_destination, :destinationUrl],
15
+ [:status, :status]
16
+ ]
17
+
18
+ @status_map = [
19
+ [:id,:id],
20
+ [:quality,:qualityScore],
21
+ [:status,:status]
22
+ ]
23
+
24
+ def self.get( auth, ids )
25
+ ids = to_json_string( ids )
26
+ body = { 'idList' => ids }
27
+ response = request( auth, Service, 'getInfoByIdList', body )
28
+ process( response, 'keywordList'){ |x| reverse_type( x['item'] ) }
29
+ end
30
+
31
+ def self.add( auth, keywords )
32
+ keyword_types = make_type( keywords ).to_json
33
+ body = { 'keywords' => keyword_types}
34
+ response = request( auth, Service, 'add', body )
35
+ process( response, 'keywordIdList'){ |x| to_id_hash_list( x['item'] ) }
36
+ end
37
+
38
+ # helper function for self.add() method
39
+ private
40
+ def self.to_id_hash_list( str )
41
+ reuturn [] if str == nil
42
+ str = [str] unless str.is_a?Array
43
+ x= []
44
+ str.each{ |i| x << { id: i.to_i } }
45
+ return x
46
+ end
47
+
48
+ def self.update( auth, keywords )
49
+ keyword_types = make_type( keywords ).to_json
50
+ body = { 'keywords' => keyword_types}
51
+ response = request( auth, Service, 'update', body )
52
+ process( response, 'affectedRecords', 'failKeywordIds' ){ |x| x }
53
+ end
54
+
55
+ # 对update的再封装实现activate方法
56
+ def self.activate( auth, ids )
57
+ keywords = []
58
+ ids.each{ |id| keywords << { id: id, status:'enable'} }
59
+ update( auth, keywords )
60
+ end
61
+
62
+ def self.delete( auth, ids )
63
+ body = { 'idList' => to_json_string( ids ) }
64
+ response = request( auth, Service, 'deleteByIdList', body )
65
+ process( response, 'affectedRecords' ){ |x| x }
66
+ end
67
+
68
+ def self.status( auth, ids )
69
+ body = { idList: to_json_string( ids ) }
70
+ response = request( auth, Service, 'getStatusByIdList', body )
71
+ process( response, 'keywordList' ){ |x| reverse_type( x['item'], @status_map ) }
72
+ end
73
+
74
+ # quality 本质上和 status 在一个方法里面
75
+ def self.quality( auth, ids )
76
+ status( auth, ids)
77
+ end
78
+
79
+ def self.search_id_by_group_id( auth, id, status = nil, match_type = nil )
80
+ # 处理条件
81
+ body = {}
82
+ body['status'] = status if status
83
+ body['matchType'] = match_type if match_type
84
+ body['groupId'] = id
85
+ response = request( auth, Service, 'getIdListByGroupId', body )
86
+ # 伪装成百度接口
87
+ process( response, 'keywordIdList' ){
88
+ |x|
89
+ [ { group_id:id, keyword_ids:to_id_list( x==nil ? nil: x['item'] ) } ]
90
+ }
91
+ end
92
+
93
+ # combine search_id and get to provide another method
94
+ def self.search_by_group_id( auth, id )
95
+ keyword_ids = search_id_by_group_id( auth, id )[:result][0][:keyword_ids]
96
+ response = get( auth, keyword_ids )
97
+ if response[:succ]
98
+ # 伪装成百度接口
99
+ response[:result] = [ { group_id:id, keywords:response[:result] } ]
100
+ end
101
+ return response
102
+ end
103
+
104
+ def self.getChangedIdList
105
+ # unimplemented
106
+ end
107
+
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,64 @@
1
+ # -*- coding:utf-8 -*-
2
+ module PPC
3
+ module API
4
+ class Qihu
5
+ class Plan < Qihu
6
+ Service = 'campaign'
7
+
8
+ @map = [
9
+ [:id, :id],
10
+ [:name,:name],
11
+ [:budget, :budget],
12
+ [:region, :region],
13
+ [:schedule, :schedule],
14
+ [:startDate, :startDate],
15
+ [:endDate, :endDate ],
16
+ [:status,:status],
17
+ [:extend_ad_type,:extendAdType]
18
+ ]
19
+
20
+
21
+ def self.get( auth, ids )
22
+ '''
23
+ :Type ids: ( Array of ) String or integer
24
+ '''
25
+ ids = to_json_string( ids )
26
+ body = { ' idList' => ids }
27
+ response = request( auth, Service, 'getInfoByIdList', body )
28
+ process( response, 'campaignList' ){ |x| reverse_type( x['item'] ) }
29
+ end
30
+
31
+ # move getCampaignId to plan module for operation call
32
+ def self.ids( auth )
33
+ response = request( auth, 'account', 'getCampaignIdList' )
34
+ process( response, 'campaignIdList' ){ |x| to_id_list( x['item'])}
35
+ end
36
+
37
+ # combine two original method to provice new method
38
+ def self.all( auth )
39
+ plan_ids = ids( auth )[:result]
40
+ get( auth, plan_ids )
41
+ end
42
+
43
+ # 奇虎计划API不提供批量服务
44
+ def self.add( auth, plan )
45
+ response = request( auth, Service, 'add', make_type( plan )[0])
46
+ # 这里将返回的简单int做一个array和hash的封装一保证接口和百度,搜狗的一致性
47
+ process( response, 'id' ){ |x| [ { id:x.to_i } ] }
48
+ end
49
+
50
+ def self.update( auth, plan )
51
+ response = request( auth, Service, 'update', make_type( plan )[0])
52
+ #同上,保证接口一致性
53
+ process( response, 'id' ){ |x| [ { id:x.to_i } ] }
54
+ end
55
+
56
+ def self.delete( auth, id )
57
+ response = request( auth, Service, 'deleteById', { id: id } )
58
+ process( response, 'affectedRecords' ){ |x| x == '1'? 'success' : 'fail' }
59
+ end
60
+
61
+ end
62
+ end
63
+ end
64
+ end