autometal-piwik 0.6.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/License.txt +22 -0
- data/README.md +80 -76
- data/Rakefile +1 -33
- data/autometal-piwik.gemspec +19 -54
- data/bin/piwik-console +31 -0
- data/lib/piwik.rb +17 -5
- data/lib/piwik/actions.rb +59 -0
- data/lib/piwik/annotations.rb +41 -0
- data/lib/piwik/api.rb +21 -0
- data/lib/piwik/api_module.rb +97 -0
- data/lib/piwik/api_response.rb +6 -0
- data/lib/piwik/api_scope.rb +32 -0
- data/lib/piwik/base.rb +156 -69
- data/lib/piwik/custom_variables.rb +8 -0
- data/lib/piwik/data_methods.rb +54 -0
- data/lib/piwik/example_api.rb +15 -0
- data/lib/piwik/goals.rb +40 -0
- data/lib/piwik/image_graph.rb +7 -0
- data/lib/piwik/languages_manager.rb +13 -0
- data/lib/piwik/live.rb +8 -0
- data/lib/piwik/metadata_api.rb +21 -0
- data/lib/piwik/mobile_messaging.rb +16 -0
- data/lib/piwik/multi_sites.rb +8 -0
- data/lib/piwik/pdf_reports.rb +12 -0
- data/lib/piwik/provider.rb +7 -0
- data/lib/piwik/referers.rb +62 -0
- data/lib/piwik/seo.rb +7 -0
- data/lib/piwik/site.rb +50 -250
- data/lib/piwik/sites_manager.rb +70 -0
- data/lib/piwik/transitions.rb +28 -0
- data/lib/piwik/typecast.rb +19 -0
- data/lib/piwik/user.rb +7 -126
- data/lib/piwik/user_country.rb +12 -0
- data/lib/piwik/user_settings.rb +16 -0
- data/lib/piwik/users_manager.rb +52 -0
- data/lib/piwik/version.rb +3 -0
- data/lib/piwik/visit_frequency.rb +7 -0
- data/lib/piwik/visit_time.rb +9 -0
- data/lib/piwik/visitor_interest.rb +10 -0
- data/lib/piwik/visits_summary.rb +53 -0
- data/lib/string.rb +11 -0
- data/spec/actions_spec.rb +19 -0
- data/spec/api_spec.rb +12 -0
- data/spec/custom_variables_spec.rb +11 -0
- data/spec/files/API.get.xml +28 -0
- data/spec/files/API.getDefaultMetricTranslations.xml +39 -0
- data/spec/files/API.getDefaultMetrics.xml +8 -0
- data/spec/files/API.getDefaultMetricsDocumentation.xml +15 -0
- data/spec/files/API.getDefaultProcessedMetrics.xml +9 -0
- data/spec/files/API.getHeaderLogoUrl.xml +2 -0
- data/spec/files/API.getLogoUrl.xml +2 -0
- data/spec/files/API.getMetadata.xml +42 -0
- data/spec/files/API.getPiwikVersion.xml +2 -0
- data/spec/files/API.getProcessedReport.xml +1227 -0
- data/spec/files/API.getReportMetadata.xml +1347 -0
- data/spec/files/API.getRowEvolution.xml +4 -0
- data/spec/files/API.getSegmentsMetadata.xml +365 -0
- data/spec/files/API.getSettings.xml +7 -0
- data/spec/files/Actions.GetPageUrl.xml +20 -0
- data/spec/files/Actions.get.xml +11 -0
- data/spec/files/Actions.getDownloads.xml +19 -0
- data/spec/files/Actions.getEntryPageTitles.xml +88 -0
- data/spec/files/Actions.getEntryPageUrls.xml +93 -0
- data/spec/files/Actions.getExitPageTitles.xml +88 -0
- data/spec/files/Actions.getExitPageUrls.xml +93 -0
- data/spec/files/Actions.getOutlink.xml +12 -0
- data/spec/files/Actions.getOutlinks.xml +100 -0
- data/spec/files/Actions.getPageTitles.xml +134 -0
- data/spec/files/Actions.getPageUrls.xml +129 -0
- data/spec/files/Annotations.add.xml +11 -0
- data/spec/files/Annotations.getAll.xml +34 -0
- data/spec/files/Annotations.getAnnotationCountForDates.xml +12 -0
- data/spec/files/CustomVariables.getCustomVariables.xml +32 -0
- data/spec/files/ExampleAPI.getAnswerToLife.xml +2 -0
- data/spec/files/ExampleAPI.getCompetitionDatatable.xml +12 -0
- data/spec/files/ExampleAPI.getDescriptionArray.xml +8 -0
- data/spec/files/ExampleAPI.getMoreInformationAnswerToLife.xml +2 -0
- data/spec/files/ExampleAPI.getMultiArray.xml +22 -0
- data/spec/files/ExampleAPI.getNull.xml +4 -0
- data/spec/files/ExampleAPI.getObject.xml +4 -0
- data/spec/files/ExampleAPI.getPiwikVersion.xml +2 -0
- data/spec/files/ExampleAPI.getSum.xml +2 -0
- data/spec/files/Goals.get.xml +7 -0
- data/spec/files/Goals.getDaysToConversion.xml +59 -0
- data/spec/files/Goals.getGoals.xml +39 -0
- data/spec/files/Goals.getVisitsUntilConversion.xml +55 -0
- data/spec/files/ImageGraph.get.xml +0 -0
- data/spec/files/LanguagesManager.getAvailableLanguageNames.xml +233 -0
- data/spec/files/LanguagesManager.getAvailableLanguages.xml +49 -0
- data/spec/files/LanguagesManager.isLanguageAvailable.xml +2 -0
- data/spec/files/Live.getCounters.xml +8 -0
- data/spec/files/Live.getLastVisitsDetails.xml +768 -0
- data/spec/files/MultiSites.getAll.xml +2 -0
- data/spec/files/MultiSites.getOne.xml +11 -0
- data/spec/files/PDFReports.getReports.xml +35 -0
- data/spec/files/Provider.getProvider.xml +113 -0
- data/spec/files/Referers.getCampaigns.xml +2 -0
- data/spec/files/Referers.getKeywords.xml +145 -0
- data/spec/files/Referers.getKeywordsForPageUrl.xml +8 -0
- data/spec/files/Referers.getNumberOfDistinctCampaigns.xml +2 -0
- data/spec/files/Referers.getNumberOfDistinctKeywords.xml +2 -0
- data/spec/files/Referers.getNumberOfDistinctSearchEngines.xml +2 -0
- data/spec/files/Referers.getNumberOfDistinctWebsites.xml +2 -0
- data/spec/files/Referers.getNumberOfDistinctWebsitesUrls.xml +2 -0
- data/spec/files/Referers.getRefererType.xml +82 -0
- data/spec/files/Referers.getSearchEngines.xml +112 -0
- data/spec/files/Referers.getSocials.xml +2 -0
- data/spec/files/Referers.getUrlsForSocial.xml +2 -0
- data/spec/files/Referers.getWebsites.xml +386 -0
- data/spec/files/SEO.getRank.xml +33 -0
- data/spec/files/SitesManager.addSite.xml +1 -0
- data/spec/files/SitesManager.getAllSites.xml +63 -0
- data/spec/files/SitesManager.getAllSitesId.xml +4 -0
- data/spec/files/SitesManager.getCurrencyList.xml +165 -0
- data/spec/files/SitesManager.getCurrencySymbols.xml +165 -0
- data/spec/files/SitesManager.getDefaultCurrency.xml +2 -0
- data/spec/files/SitesManager.getDefaultTimezone.xml +2 -0
- data/spec/files/SitesManager.getExcludedIpsGlobal.xml +2 -0
- data/spec/files/SitesManager.getExcludedQueryParametersGlobal.xml +2 -0
- data/spec/files/SitesManager.getJavascriptTag.xml +14 -0
- data/spec/files/SitesManager.getSearchCategoryParametersGlobal.xml +2 -0
- data/spec/files/SitesManager.getSearchKeywordParametersGlobal.xml +2 -0
- data/spec/files/SitesManager.getSiteFromId.xml +18 -0
- data/spec/files/SitesManager.getSiteUrlsFromId.xml +4 -0
- data/spec/files/SitesManager.getSitesGroups.xml +4 -0
- data/spec/files/SitesManager.getSitesIdFromSiteUrl.xml +2 -0
- data/spec/files/SitesManager.getSitesIdWithAdminAccess.xml +4 -0
- data/spec/files/SitesManager.getSitesIdWithAtLeastViewAccess.xml +4 -0
- data/spec/files/SitesManager.getSitesIdWithViewAccess.xml +2 -0
- data/spec/files/SitesManager.getSitesIdWithVisits.xml +2 -0
- data/spec/files/SitesManager.getSitesWithAdminAccess.xml +63 -0
- data/spec/files/SitesManager.getSitesWithAtLeastViewAccess.xml +18 -0
- data/spec/files/SitesManager.getSitesWithViewAccess.xml +2 -0
- data/spec/files/SitesManager.getTimezonesList.xml +509 -0
- data/spec/files/SitesManager.getUniqueSiteTimezones.xml +4 -0
- data/spec/files/Transitions.getTranslations.xml +37 -0
- data/spec/files/UserCountry.getCity.xml +221 -0
- data/spec/files/UserCountry.getContinent.xml +185 -0
- data/spec/files/UserCountry.getCountry.xml +154 -0
- data/spec/files/UserCountry.getLocationFromIP.xml +17 -0
- data/spec/files/UserCountry.getNumberOfDistinctCountries.xml +2 -0
- data/spec/files/UserCountry.getRegion.xml +269 -0
- data/spec/files/UserSettings.getBrowser.xml +47 -0
- data/spec/files/UserSettings.getBrowserType.xml +58 -0
- data/spec/files/UserSettings.getBrowserVersion.xml +39 -0
- data/spec/files/UserSettings.getConfiguration.xml +43 -0
- data/spec/files/UserSettings.getMobileVsDesktop.xml +36 -0
- data/spec/files/UserSettings.getOS.xml +27 -0
- data/spec/files/UserSettings.getOSFamily.xml +102 -0
- data/spec/files/UserSettings.getPlugin.xml +63 -0
- data/spec/files/UserSettings.getResolution.xml +33 -0
- data/spec/files/UserSettings.getWideScreen.xml +47 -0
- data/spec/files/UsersManager.getSitesAccessFromUser.xml +4 -0
- data/spec/files/UsersManager.getUser.xml +10 -0
- data/spec/files/UsersManager.getUsers.xml +11 -0
- data/spec/files/UsersManager.getUsersAccessFromSite.xml +2 -0
- data/spec/files/UsersManager.getUsersLogin.xml +4 -0
- data/spec/files/UsersManager.getUsersSitesFromAccess.xml +2 -0
- data/spec/files/UsersManager.getUsersWithSiteAccess.xml +2 -0
- data/spec/files/UsersManager.userExists.xml +2 -0
- data/spec/files/VisitFrequency.get.xml +13 -0
- data/spec/files/VisitTime.getByDayOfWeek.xml +43 -0
- data/spec/files/VisitTime.getVisitInformationPerLocalTime.xml +83 -0
- data/spec/files/VisitTime.getVisitInformationPerServerTime.xml +87 -0
- data/spec/files/VisitorInterest.getNumberOfVisitsByDaysSinceLast.xml +63 -0
- data/spec/files/VisitorInterest.getNumberOfVisitsByVisitCount.xml +73 -0
- data/spec/files/VisitorInterest.getNumberOfVisitsPerPage.xml +43 -0
- data/spec/files/VisitorInterest.getNumberOfVisitsPerVisitDuration.xml +43 -0
- data/spec/files/VisitsSummary.get.xml +13 -0
- data/spec/files/VisitsSummary.getActions.xml +2 -0
- data/spec/files/VisitsSummary.getBounceCount.xml +2 -0
- data/spec/files/VisitsSummary.getMaxActions.xml +2 -0
- data/spec/files/VisitsSummary.getSumVisitsLength.xml +2 -0
- data/spec/files/VisitsSummary.getSumVisitsLengthPretty.xml +2 -0
- data/spec/files/VisitsSummary.getUniqueVisitors.xml +2 -0
- data/spec/files/VisitsSummary.getVisits.xml +2 -0
- data/spec/files/VisitsSummary.getVisitsConverted.xml +2 -0
- data/spec/files/failure.xml +3 -0
- data/spec/files/success.xml +3 -0
- data/spec/goals_spec.rb +14 -0
- data/spec/image_graph_spec.rb +12 -0
- data/spec/languages_manager_spec.rb +13 -0
- data/spec/live_spec.rb +13 -0
- data/spec/mobile_messaging_spec.rb +10 -0
- data/spec/multi_sites_spec.rb +11 -0
- data/spec/pdf_reports_spec.rb +11 -0
- data/spec/provider_spec.rb +12 -0
- data/spec/referers_spec.rb +46 -0
- data/spec/seo_spec.rb +15 -0
- data/spec/site_spec.rb +104 -0
- data/spec/sites_manager_spec.rb +30 -0
- data/spec/spec_helper.rb +76 -0
- data/spec/transitions_spec.rb +13 -0
- data/spec/user_country_spec.rb +33 -0
- data/spec/user_settings_spec.rb +50 -0
- data/spec/user_spec.rb +32 -0
- data/spec/users_manager_spec.rb +26 -0
- data/spec/visit_frequency_spec.rb +11 -0
- data/spec/visit_time_spec.rb +22 -0
- data/spec/visitor_interest_spec.rb +30 -0
- data/spec/visits_summary_spec.rb +47 -0
- metadata +426 -99
- data/.document +0 -5
- data/LICENSE +0 -7
- data/VERSION +0 -1
- data/lib/piwik/trackable.rb +0 -80
- data/script/console +0 -10
- data/test/files/config/example_piwik.yml +0 -4
- data/test/piwik_test.rb +0 -128
- data/test/test_helper.rb +0 -12
@@ -0,0 +1,41 @@
|
|
1
|
+
module Piwik
|
2
|
+
class Annotations < ApiModule
|
3
|
+
available_methods %W{
|
4
|
+
get
|
5
|
+
add
|
6
|
+
save
|
7
|
+
delete
|
8
|
+
getAll
|
9
|
+
getAnnotationCountForDates
|
10
|
+
}
|
11
|
+
|
12
|
+
scoped_methods do
|
13
|
+
def load note_id
|
14
|
+
get(defaults.merge(:idNote => note_id))
|
15
|
+
end
|
16
|
+
|
17
|
+
def all params = {}
|
18
|
+
getAll(defaults.merge(params))
|
19
|
+
end
|
20
|
+
|
21
|
+
# params: ( date, note, starred = '0')
|
22
|
+
def add params = {}
|
23
|
+
super(defaults.merge(params))
|
24
|
+
end
|
25
|
+
|
26
|
+
# params: (date = '', note = '', starred = '')
|
27
|
+
def update note_id, params = {}
|
28
|
+
save(defaults.merge(params).merge(:idNote => note_id))
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete note_id
|
32
|
+
super(defaults.merge(:idNote => note_id))
|
33
|
+
end
|
34
|
+
|
35
|
+
# params: (date, period, lastN = '', getAnnotationText = '')
|
36
|
+
def count_for_dates params = {}
|
37
|
+
getAnnotationCountForDates(defaults.merge(params))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/piwik/api.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Piwik
|
2
|
+
class API < ApiModule
|
3
|
+
available_methods %W{
|
4
|
+
getPiwikVersion
|
5
|
+
getSettings
|
6
|
+
getDefaultMetricTranslations
|
7
|
+
getDefaultMetrics
|
8
|
+
getDefaultProcessedMetrics
|
9
|
+
getDefaultMetricsDocumentation
|
10
|
+
getSegmentsMetadata
|
11
|
+
getLogoUrl
|
12
|
+
getHeaderLogoUrl
|
13
|
+
getMetadata
|
14
|
+
getReportMetadata
|
15
|
+
getProcessedReport
|
16
|
+
get
|
17
|
+
getRowEvolution
|
18
|
+
getBulkRequest
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Piwik
|
2
|
+
class ApiModule < Base
|
3
|
+
include Piwik::DataMethods
|
4
|
+
|
5
|
+
# returns default API params, used all over the place, especially in <tt>scoped_methods</tt>
|
6
|
+
def self.defaults
|
7
|
+
{:period => :day, :date => Date.today, @obj.id_attr => @obj.id}
|
8
|
+
end
|
9
|
+
|
10
|
+
# Catch incoming method calls and try to format them and send them over to the api
|
11
|
+
def self.method_missing(method, *args, &block)
|
12
|
+
formatted_method = method.to_s.camelize(:lower)
|
13
|
+
formatted_method = formatted_method.gsub(/ip$/i,'IP').gsub(/os/i,'OS') # Lame
|
14
|
+
# connect to API if this is a valid-looking method in the current class context
|
15
|
+
if @available_methods.include?(formatted_method)
|
16
|
+
handle_api_call(formatted_method, args.first)
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# allows the addition of scoped methods. It's basically a class << self wrapper
|
23
|
+
# mostly added to make ApiModule code more self-explanatory
|
24
|
+
# the @obj instance variable is set in the api_scope call. This is not very clean or anything,
|
25
|
+
# and I am still researching a better way to do it,
|
26
|
+
# but the Piwik::Site API is certainly much better to work with due to this
|
27
|
+
def self.scoped_methods &block
|
28
|
+
if block_given?
|
29
|
+
extension = Module.new(&Proc.new)
|
30
|
+
self.extend(extension)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.available_methods method_array
|
35
|
+
@available_methods = method_array
|
36
|
+
@available_methods.each do |method|
|
37
|
+
class_eval %{
|
38
|
+
class #{self.api_call_to_const(method)} < Piwik::ApiResponse
|
39
|
+
end
|
40
|
+
}, __FILE__, __LINE__
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.api_call_to_const string, full = false
|
45
|
+
# We can get rid of the get prefix
|
46
|
+
string = case string
|
47
|
+
when /[A-Z]{1}[a-z]*\.[get|add|delete|save]$/,'get','add','delete','save'
|
48
|
+
string.camelize
|
49
|
+
else
|
50
|
+
string.gsub(/get|save|add|delete/, '')
|
51
|
+
end
|
52
|
+
string = string.split('.').map {|s| s.camelize }.join('::')
|
53
|
+
full ? "Piwik::#{string}" : string
|
54
|
+
end
|
55
|
+
protected
|
56
|
+
# Attempt an API call request
|
57
|
+
def self.handle_api_call method, params
|
58
|
+
method_name = "#{self.to_s.gsub('Piwik::','')}.#{method}"
|
59
|
+
config = load_config_from_file
|
60
|
+
xml = self.call(method_name, params, config[:piwik_url], config[:auth_token])
|
61
|
+
data = (xml.is_a?(String) && xml.is_binary_data?) ? xml : XmlSimple.xml_in(xml, {'ForceArray' => false})
|
62
|
+
if data.is_a?(String) && data.is_binary_data?
|
63
|
+
api_call_to_const(method_name,true).constantize.new(:data => [], :value => data)
|
64
|
+
elsif data.is_a?(String)
|
65
|
+
api_call_to_const(method_name,true).constantize.new(:data => [], :value => data)
|
66
|
+
elsif data['row'].present?
|
67
|
+
api_call_to_const(method_name,true).constantize.new(:data => data['row'])
|
68
|
+
elsif data.is_a?(Hash)
|
69
|
+
api_call_to_const(method_name,true).constantize.new(:data => data)
|
70
|
+
else
|
71
|
+
api_call_to_const(method_name,true).constantize.new(:data => [])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Attempt an API call request
|
76
|
+
def self.api_call method, params
|
77
|
+
method_name = "#{self.to_s.gsub('Piwik::','')}.#{method}"
|
78
|
+
config = load_config_from_file
|
79
|
+
if params.is_a?(OpenStruct)
|
80
|
+
params = params.marshal_dump
|
81
|
+
end
|
82
|
+
xml = self.call(method_name, params, config[:piwik_url], config[:auth_token])
|
83
|
+
data = XmlSimple.xml_in(xml, {'ForceArray' => false})
|
84
|
+
if data.is_a?(String)
|
85
|
+
data
|
86
|
+
elsif data['row'].present?
|
87
|
+
data['row']
|
88
|
+
elsif data.is_a?(Hash) and data['success'].is_a?(Hash)
|
89
|
+
true
|
90
|
+
elsif data.is_a?(Hash)
|
91
|
+
data
|
92
|
+
else
|
93
|
+
[]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Piwik
|
2
|
+
# Used to extend a wrapper class with class-aware api calls, allowing users to use a more DRY api interface.
|
3
|
+
# Example:
|
4
|
+
#
|
5
|
+
# site = Piwik::Site.load(7)
|
6
|
+
# p = site.actions # returns an extended version of the Piwik::Actions api module
|
7
|
+
# => Piwik::Actions
|
8
|
+
# p.outlinks # equivalent to Piwik::Actions.getOutlinks(:idSite => 7)
|
9
|
+
# => #<Piwik::Actions::Outlinks @data=[snip]>
|
10
|
+
module ApiScope
|
11
|
+
def self.included(base)
|
12
|
+
base.extend ClassMethods
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def api_scope name, scope_options = {}, &block
|
17
|
+
name = name.to_sym
|
18
|
+
class_name = "Piwik::#{scope_options[:class_name] ? scope_options[:class_name] : name.to_s.camelize}"
|
19
|
+
extension = Module.new(&Proc.new) if block_given?
|
20
|
+
instance_eval do
|
21
|
+
define_method name do
|
22
|
+
klass = class_name.constantize
|
23
|
+
klass.extend(extension) if block_given?
|
24
|
+
klass.instance_variable_set(:@obj, self)
|
25
|
+
klass
|
26
|
+
end
|
27
|
+
end
|
28
|
+
self
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/piwik/base.rb
CHANGED
@@ -1,23 +1,20 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'cgi'
|
3
|
-
require '
|
4
|
-
require 'json/ext'
|
3
|
+
require 'yaml'
|
5
4
|
require 'rest_client'
|
5
|
+
require 'xmlsimple'
|
6
|
+
require 'ostruct'
|
6
7
|
|
7
8
|
module Piwik
|
8
9
|
class ApiError < StandardError; end
|
9
10
|
class MissingConfiguration < ArgumentError; end
|
10
11
|
class UnknownSite < ArgumentError; end
|
11
12
|
class UnknownUser < ArgumentError; end
|
12
|
-
|
13
|
-
|
14
|
-
mattr_accessor :auth_token
|
15
|
-
|
16
|
-
def self.is_configured?
|
17
|
-
@@piwik_url!=nil && @@auth_token!=nil
|
18
|
-
end
|
19
|
-
|
13
|
+
class UnknownGoal < ArgumentError; end
|
14
|
+
|
20
15
|
class Base
|
16
|
+
include Piwik::Typecast
|
17
|
+
include Piwik::ApiScope
|
21
18
|
@@template = <<-EOF
|
22
19
|
# .piwik
|
23
20
|
#
|
@@ -29,29 +26,80 @@ module Piwik
|
|
29
26
|
piwik_url:
|
30
27
|
auth_token:
|
31
28
|
EOF
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
else
|
41
|
-
# puts "config_file from ~/.piwik"
|
42
|
-
File.join( ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH'] || ".", '.piwik' )
|
29
|
+
|
30
|
+
# common constructor, using ostruct for attribute storage
|
31
|
+
attr_accessor :attributes
|
32
|
+
def initialize params = {}
|
33
|
+
@attributes = OpenStruct.new
|
34
|
+
params.map do |k,v|
|
35
|
+
@attributes.send(:"#{k}=",typecast(v))
|
36
|
+
end
|
43
37
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
38
|
+
|
39
|
+
def id_attr
|
40
|
+
self.class.id_attr
|
41
|
+
end
|
42
|
+
|
43
|
+
def save
|
44
|
+
if new?
|
45
|
+
resp = collection.add(attributes)
|
46
|
+
attributes = resp.attributes
|
47
|
+
true
|
48
|
+
else
|
49
|
+
collection.save(attributes)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
alias :update :save
|
54
|
+
|
55
|
+
def delete
|
56
|
+
collection.delete(attributes)
|
57
|
+
end
|
58
|
+
alias :destroy :delete
|
59
|
+
|
60
|
+
# Returns <tt>true</tt> if the current site does not exists in the Piwik yet.
|
61
|
+
def new?
|
62
|
+
begin
|
63
|
+
if respond_to?(:id)
|
64
|
+
id.nil? && created_at.blank?
|
65
|
+
else
|
66
|
+
created_at.blank?
|
67
|
+
end
|
68
|
+
|
69
|
+
rescue Exception => e
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
#id will try and return the value of the Piwik item id if it exists
|
75
|
+
def id
|
76
|
+
begin
|
77
|
+
if self.class == Piwik::Site
|
78
|
+
self.idsite
|
79
|
+
else
|
80
|
+
attributes.send(:"id#{self.class.to_s.gsub('Piwik::','')}")
|
81
|
+
end
|
82
|
+
rescue Exception => e
|
83
|
+
$stderr.puts e
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
#created_at will try and return the value of the Piwik item id if it exists
|
88
|
+
def created_at
|
89
|
+
attributes.send(:ts_created) rescue nil
|
90
|
+
end
|
91
|
+
|
92
|
+
# delegate attribute calls to @attributes storage
|
93
|
+
def method_missing(method,*args,&block)
|
94
|
+
if self.attributes.respond_to?(method)
|
95
|
+
self.attributes.send(method,*args,&block)
|
96
|
+
else
|
97
|
+
super
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def parse_xml xml; self.class.parse_xml xml; end
|
102
|
+
|
55
103
|
# Calls the supplied Piwik API method, with the supplied parameters.
|
56
104
|
#
|
57
105
|
# Returns a string containing the XML reply from Piwik, or raises a
|
@@ -61,49 +109,88 @@ EOF
|
|
61
109
|
self.class.call(method, params, config[:piwik_url], config[:auth_token])
|
62
110
|
end
|
63
111
|
|
64
|
-
|
65
|
-
|
66
|
-
# Returns the object parsed from JSON reply from Piwik, or raises a
|
67
|
-
# <tt>Piwik::ApiError</tt> exception with the error message returned by Piwik
|
68
|
-
# in case it receives an error.
|
69
|
-
def self.call(method, params={}, piwik_url=nil, auth_token=nil)
|
70
|
-
raise MissingConfiguration, "Please edit #{config_file} to include your piwik url and auth_token or configure Piwik.piwik_url and Piwik.auth_token before use" if piwik_url.nil? || auth_token.nil?
|
71
|
-
url = "#{piwik_url}/?module=API&format=json&method=#{method}"
|
72
|
-
url << "&token_auth=#{auth_token}" unless auth_token.nil?
|
73
|
-
params.each { |k, v| url << "&#{k}=#{CGI.escape(v.to_s)}" }
|
74
|
-
verbose_obj_save = $VERBOSE
|
75
|
-
$VERBOSE = nil # Suppress "warning: peer certificate won't be verified in this SSL session"
|
76
|
-
json = RestClient.get(url)
|
77
|
-
$VERBOSE = verbose_obj_save
|
78
|
-
result = self.parse_json json
|
79
|
-
if json =~ /error message=/
|
80
|
-
raise ApiError, result['error']['message'] if result['error']
|
81
|
-
end
|
82
|
-
result
|
112
|
+
def config
|
113
|
+
@config ||= self.class.load_config_from_file
|
83
114
|
end
|
84
115
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
116
|
+
def collection
|
117
|
+
self.class.collection
|
118
|
+
end
|
119
|
+
|
120
|
+
class << self
|
121
|
+
def collection
|
122
|
+
"#{self.to_s.pluralize}".safe_constantize
|
123
|
+
end
|
124
|
+
|
125
|
+
# This is required to normalize the API responses when the Rails XmlSimple version is used
|
126
|
+
def parse_xml xml
|
127
|
+
result = XmlSimple.xml_in(xml, {'ForceArray' => false})
|
128
|
+
result = result['result'] if result['result']
|
129
|
+
result
|
130
|
+
end
|
131
|
+
|
132
|
+
def load id
|
133
|
+
collection.get(id_attr => id)
|
134
|
+
end
|
135
|
+
alias :reload :load
|
136
|
+
|
137
|
+
# Calls the supplied Piwik API method, with the supplied parameters.
|
138
|
+
#
|
139
|
+
# Returns a string containing the XML reply from Piwik, or raises a
|
140
|
+
# <tt>Piwik::ApiError</tt> exception with the error message returned by Piwik
|
141
|
+
# in case it receives an error.
|
142
|
+
def call(method, params, piwik_url=nil, auth_token=nil)
|
143
|
+
params ||= {}
|
144
|
+
raise MissingConfiguration, "Please edit ~/.piwik to include your piwik url and auth_key" if piwik_url.nil? || auth_token.nil?
|
145
|
+
url = "#{piwik_url}/index.php?"
|
146
|
+
params.merge!({:module => 'API', :format => 'xml', :method => method})
|
147
|
+
params.merge!({:token_auth => auth_token}) unless auth_token.nil?
|
148
|
+
url << params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&')
|
149
|
+
verbose_obj_save = $VERBOSE
|
150
|
+
$VERBOSE = nil # Suppress "warning: peer certificate won't be verified in this SSL session"
|
151
|
+
xml = RestClient.get(url)
|
152
|
+
$VERBOSE = verbose_obj_save
|
153
|
+
if xml.is_a?(String) && xml.force_encoding('BINARY').is_binary_data?
|
154
|
+
xml.force_encoding('BINARY')
|
155
|
+
elsif xml =~ /error message=/
|
156
|
+
result = XmlSimple.xml_in(xml, {'ForceArray' => false})
|
157
|
+
raise ApiError, result['error']['message'] if result['error']
|
158
|
+
else
|
159
|
+
xml
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Checks for the config, creates it if not found
|
164
|
+
def load_config_from_file
|
165
|
+
# Useful for testing or embedding credentials - although as always
|
166
|
+
# it is not recommended to embed any kind of credentials in source code for security reasons
|
167
|
+
return { :piwik_url => PIWIK_URL, :auth_token => PIWIK_TOKEN } if PIWIK_URL.present? and PIWIK_TOKEN.present?
|
168
|
+
config = {}
|
169
|
+
if defined?(RAILS_ROOT) and RAILS_ROOT != nil
|
170
|
+
home = RAILS_ROOT
|
171
|
+
filename = "config/piwik.yml"
|
172
|
+
else
|
173
|
+
home = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH'] || "."
|
174
|
+
filename = ".piwik"
|
175
|
+
end
|
176
|
+
temp_config = if File.exists?(File.join(home,filename))
|
177
|
+
YAML::load(open(File.join(home,filename)))
|
178
|
+
else
|
179
|
+
open(File.join(home,filename),'w') { |f| f.puts @@template }
|
180
|
+
YAML::load(@@template)
|
181
|
+
end
|
182
|
+
temp_config.each { |k,v| config[k.to_sym] = v } if temp_config
|
183
|
+
if config[:piwik_url] == nil || config[:auth_token] == nil
|
184
|
+
if defined?(RAILS_ROOT) and RAILS_ROOT != nil
|
185
|
+
raise MissingConfiguration, "Please edit ./config/piwik.yml to include your piwik url and auth_key"
|
95
186
|
else
|
96
|
-
|
97
|
-
YAML::load(@@template)
|
187
|
+
raise MissingConfiguration, "Please edit ~/.piwik to include your piwik url and auth_key"
|
98
188
|
end
|
99
|
-
|
189
|
+
|
100
190
|
end
|
101
|
-
|
102
|
-
#cache settings
|
103
|
-
Piwik.piwik_url = config[:piwik_url]
|
104
|
-
Piwik.auth_token = config[:auth_token]
|
191
|
+
config
|
105
192
|
end
|
106
|
-
config
|
107
193
|
end
|
108
194
|
end
|
109
195
|
end
|
196
|
+
|