guidepost 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62c2acd52325cb79660d168c94639ece0246665293d8d5a4008b2798e64b9f73
4
- data.tar.gz: 71e6410cfad4f1c49f2308d7b8a5354637b1da7cef6e2050731dc8958502fa2d
3
+ metadata.gz: 07224025b0722a20214c83ebac582ad2598712479e6b0bf70d42865a1e565128
4
+ data.tar.gz: fa6d4711fcd19040e8bf34c2c61387eea7439e96990ff546443cc0bb4e414d55
5
5
  SHA512:
6
- metadata.gz: d8032ff476ee49c7898db53d35b3e66b25734a855a53c6fefd29ae0a74662b795a5cc38a0edefddc4e78fd754270fdb29223b94e291c645579d8d44e4ba450ec
7
- data.tar.gz: 28a241a4912b8d3f830323a63678c521b4547069df32e370cdd9631ac8d2db176d7446ce2e5436baf4c2ac3e5103d71d74af45cf21d0e680812fe5d17d7c15fc
6
+ metadata.gz: f404c59049be377e6c220ac4e9cd14333573f10334b0613fd7d7ee65952fdd9514433576a9a21a2fd8b6d46b0d8dbfda4f61e3149b0c0448a2c4806132b4eb79
7
+ data.tar.gz: c69162e260001336487daf9c15f17f5f2bea96c65c2d97233c8783edda667e96816f65a262924e4d67d1cbb30780a8c09e9e897bdfdee2f7e0b946175530090d
data/README.md CHANGED
@@ -1,17 +1,24 @@
1
1
  # Guidepost
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/guidepost.svg)](https://badge.fury.io/rb/guidepost)
4
+
3
5
  ## Purpose
4
6
 
5
- Your knowledge base is a hugely important component of your company! The purpose of this project is to help you gain more control over it.
7
+ Your knowledge base is an incredibly important component of your company, providing value to your customers, employees, and other stakeholders! The purpose of this project is to help you gain more control over it.
8
+
9
+ ## Current Use Cases
10
+
11
+ * [Back up your knowledge base to S3](#back-up-your-knowledge-base-to-s3)
12
+ * [Import your knowledge base into your application](#import-your-knowledge-base-into-your-application)
6
13
 
7
14
  ## Table of Contents
8
15
 
9
16
  * [Prerequisites/Requirements](#prerequisites-requirements)
10
- * [Current Knowledge Base Providers](#current-knowledge-base-providers)
11
- * [Current Storage Services](#current-storage-services)
17
+ * [Knowledge Base Providers](#knowledge-base-providers)
18
+ * [Storage Services](#storage-services)
12
19
  * [Installation](#installation)
13
20
  * [Environment Variables](#environment-variables)
14
- * [Current Use Cases](#current-use-cases)
21
+ * [Usage](#usage)
15
22
  * [Contact](#contact)
16
23
  * [Roadmap](#roadmap)
17
24
  * [License](#license)
@@ -21,18 +28,14 @@ Your knowledge base is a hugely important component of your company! The purpose
21
28
  * Rails 4.2+
22
29
  * Ruby 2.5+
23
30
 
24
- ### Current Knowledge Base Providers
31
+ ### Knowledge Base Providers
25
32
 
26
33
  * Zendesk
27
34
 
28
- If you're looking to use this gem, but work with providers like Freshdesk, Zoho, and Confluence, feel free to reach out!
29
-
30
- ### Current Storage Services
35
+ ### Storage Services
31
36
 
32
37
  * Amazon Simple Storage Service (Amazon S3)
33
38
 
34
- If you're looking to use this gem, but work with other storage services like Google Cloud Storage, feel free to reach out!
35
-
36
39
  ### Installation
37
40
 
38
41
  Add this line to your application's Gemfile:
@@ -68,27 +71,52 @@ ENV["#{YOUR_PROJECT_NAME}_GUIDEPOST_AWS_ACCESS_KEY_ID"]
68
71
  # The secret key associated with your AWS account
69
72
  ENV["#{YOUR_PROJECT_NAME}_GUIDEPOST_AWS_SECRET_ACCESS_KEY"]
70
73
 
74
+ # The AWS region associated with this project
75
+ ENV["#{YOUR_PROJECT_NAME}_GUIDEPOST_AWS_REGION"]
76
+
71
77
  # The name of the S3 bucket you want to upload your backups to
72
78
  ENV["#{YOUR_PROJECT_NAME}_GUIDEPOST_S3_BUCKET_NAME"]
73
79
  ```
74
80
 
75
- ### Current Use Cases
76
-
77
- * Back up your knowledge base to S3
81
+ ### Usage
78
82
 
79
83
  #### Back up your knowledge base to S3
80
84
 
85
+ ##### Implement the backup functionality in your code
86
+
81
87
  ```ruby
82
- subdomain = "example"
83
- project_name = "example"
88
+ # The subdomain of your Zendesk account
89
+ subdomain = "spotify"
90
+
91
+ # The name you want to give to your project (name your environment variables accordingly)
92
+ project_name = "employee-portal"
84
93
 
85
94
  zendesk = Guidepost::Provider::Zendesk.new(subdomain: subdomain, project_name: project_name)
86
- zendesk.backup_all_articles
95
+ zendesk.backup_all_articles(sideload: true)
87
96
  ```
88
97
 
98
+ ##### Run a script outside of your codebase
99
+
100
+ $ rake zendesk_guide:backup_articles[spotify,employee-portal]
101
+
102
+ #### Import your knowledge base into your application
103
+
104
+
105
+ ##### Generate all of the necessary model and migration files
106
+
107
+ $ rails g guidepost:models
108
+
109
+ ##### Perform all of the schema migrations
110
+
111
+ $ rails g guidepost:migrate
112
+
113
+ ##### Run a script outside of your codebase
114
+
115
+ $ rake zendesk_guide:import_guides_into_database[spotify,employee-portal]
116
+
89
117
  ## Contact
90
118
 
91
- If you find and want to address any security issues with the project, email [Kiren Srinivasan](mailto:srinitude@gmail.com.com)! For anything else, feel free to file a Github issue or tweet me [@srinitude](https://twitter.com/srinitude).
119
+ If you find and want to address any security issues with the project, email [me](mailto:srinitude@gmail.com.com)! For anything else, like bug identifications or feature requests, feel free to file a Github issue or tweet me [@srinitude](https://twitter.com/srinitude).
92
120
 
93
121
  ## Roadmap
94
122
 
@@ -98,4 +126,4 @@ If you find and want to address any security issues with the project, email [Kir
98
126
 
99
127
  ## License
100
128
 
101
- Guidepost is released under the [MIT License](LICENSE).
129
+ Guidepost is released under the [MIT License](LICENSE).
@@ -0,0 +1,19 @@
1
+ require "rails/generators/base"
2
+
3
+ module Guidepost
4
+ module Generators
5
+
6
+ class MigrateGenerator < Rails::Generators::Base
7
+ desc "This generator performs the schema and data migrations associated with your current Zendesk guides"
8
+
9
+ def self.default_generator_root
10
+ File.dirname(__FILE__)
11
+ end
12
+
13
+ def schema_migration
14
+ `rake db:migrate`
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ require "rails/generators/base"
2
+
3
+ module Guidepost
4
+ module Generators
5
+
6
+ class ModelsGenerator < Rails::Generators::Base
7
+ desc "This generator creates the migrations, models, and tests associated with your current Zendesk guides"
8
+
9
+ def self.default_generator_root
10
+ File.dirname(__FILE__)
11
+ end
12
+
13
+ def migrations
14
+ timestamp = Time.now.strftime('%Y%m%d%H%M%S')
15
+ template "migrations.rb", "db/migrate/#{timestamp}_create_zendesk_guide_models.rb"
16
+ template "zendesk_guide.rake", "lib/tasks/zendesk_guide.rake"
17
+ end
18
+
19
+ def models
20
+ model_templates = [
21
+ "zendesk_guide_category.rb",
22
+ "zendesk_guide_section.rb",
23
+ "zendesk_guide_article.rb",
24
+ "zendesk_guide_article_attachment.rb",
25
+ "zendesk_guide_permission_group.rb",
26
+ "zendesk_guide_user_segment.rb"
27
+ ]
28
+ model_templates.each do |t|
29
+ template t, "app/models/#{t}"
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,95 @@
1
+ class CreateZendeskGuideModels < ActiveRecord::Migration
2
+ def change
3
+ create_table :zendesk_guide_categories do |t|
4
+ t.integer :category_id, limit: 8
5
+ t.string :name, null: false, default: "General"
6
+ t.string :description
7
+ t.string :locale, null: false, default: "en-us"
8
+ t.string :source_locale
9
+ t.string :url
10
+ t.string :html_url
11
+ t.boolean :outdated
12
+ t.integer :position
13
+ t.timestamp :category_created_at
14
+ t.timestamp :category_updated_at
15
+ end
16
+
17
+ create_table :zendesk_guide_sections do |t|
18
+ t.integer :zendesk_guide_category_id
19
+ t.integer :category_id, limit: 8
20
+ t.integer :section_id, limit: 8
21
+ t.string :name, null: false, default: "General"
22
+ t.string :description
23
+ t.string :locale, null: false, default: "en-us"
24
+ t.string :source_locale
25
+ t.string :url
26
+ t.string :html_url
27
+ t.boolean :outdated
28
+ t.integer :position
29
+ t.timestamp :section_created_at
30
+ t.timestamp :section_updated_at
31
+ end
32
+
33
+ create_table :zendesk_guide_user_segments do |t|
34
+ t.integer :user_segment_id, limit: 8
35
+ t.string :name
36
+ t.string :user_type
37
+ t.integer :group_ids, array: true, default: [], limit: 8
38
+ t.integer :organization_ids, array: true, default: [], limit: 8
39
+ t.string :tags, array: true, default: []
40
+ t.timestamp :user_segment_created_at
41
+ t.timestamp :user_segment_updated_at
42
+ end
43
+
44
+ create_table :zendesk_guide_permission_groups do |t|
45
+ t.integer :permission_group_id, limit: 8
46
+ t.string :name
47
+ t.integer :edit, array: true, default: [], limit: 8
48
+ t.integer :publish, array: true, default: [], limit: 8
49
+ t.timestamp :permission_group_created_at
50
+ t.timestamp :permission_group_updated_at
51
+ t.boolean :built_in
52
+ end
53
+
54
+ create_table :zendesk_guide_articles do |t|
55
+ t.integer :zendesk_guide_section_id
56
+ t.integer :section_id, limit: 8
57
+ t.integer :article_id, limit: 8
58
+ t.string :url
59
+ t.string :html_url
60
+ t.string :title, null: false, default: "FAQ"
61
+ t.string :body
62
+ t.string :locale, null: false, default: "en-us"
63
+ t.string :source_locale
64
+ t.integer :author_id, limit: 8
65
+ t.boolean :comments_disabled, default: false
66
+ t.string :outdated_locales, array: true
67
+ t.string :label_names, array: true, default: []
68
+ t.boolean :draft, default: false
69
+ t.boolean :promoted, default: false
70
+ t.integer :position, default: 0
71
+ t.integer :vote_sum
72
+ t.integer :vote_count
73
+ t.integer :user_segment_id, limit: 8
74
+ t.integer :zendesk_guide_user_segment_id
75
+ t.integer :permission_group_id, limit: 8
76
+ t.integer :zendesk_guide_permission_group_id
77
+ t.timestamp :article_created_at
78
+ t.timestamp :article_edited_at
79
+ t.timestamp :article_updated_at
80
+ end
81
+
82
+ create_table :zendesk_guide_article_attachments do |t|
83
+ t.integer :zendesk_guide_article_id
84
+ t.integer :article_id, limit: 8
85
+ t.integer :article_attachment_id, limit: 8
86
+ t.string :url
87
+ t.string :file_name
88
+ t.string :content_url
89
+ t.integer :size, limit: 8
90
+ t.boolean :inline, default: false
91
+ t.timestamp :article_attachment_created_at
92
+ t.timestamp :article_attachment_updated_at
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,70 @@
1
+ namespace :zendesk_guide do
2
+
3
+ desc "Backup articles from knowledge base provider (i.e. Zendesk currently) [customize this task if you want to add more functionality]"
4
+ task :backup_articles, [:subdomain, :project_name] => :environment do |t, args|
5
+ begin
6
+ subdomain = args[:subdomain]
7
+ project_name = args[:project_name]
8
+
9
+ if subdomain.nil? || project_name.nil?
10
+ raise "Subdomain and/or project_name arguments are missing" if Rails.env.development?
11
+ end
12
+
13
+ zendesk = Guidepost::Provider::Zendesk.new(subdomain: subdomain, project_name: project_name)
14
+ zendesk.backup_all_articles(sideload: true)
15
+ rescue => e
16
+ raise e if Rails.env.development?
17
+ end
18
+ end
19
+
20
+ desc "Import guides and respective models into database [customize this task if you want to add more functionality]"
21
+ task :import_guides_into_database, [:subdomain, :project_name] => :environment do |t, args|
22
+ begin
23
+ subdomain = args[:subdomain]
24
+ project_name = args[:project_name]
25
+
26
+ if subdomain.nil? || project_name.nil?
27
+ raise "Subdomain and/or project_name arguments are missing" if Rails.env.development?
28
+ end
29
+
30
+ zendesk = Guidepost::Provider::Zendesk.new(subdomain: subdomain, project_name: project_name)
31
+ articles_sections_and_categories = zendesk.retrieve_all_articles(sideload: true)
32
+
33
+ categories = articles_sections_and_categories[:categories]
34
+ category_objects = []
35
+ ZendeskGuideCategory.find_or_create_categories(categories: categories, category_objects: category_objects)
36
+
37
+ sections = articles_sections_and_categories[:sections]
38
+ section_objects = []
39
+ ZendeskGuideSection.find_or_create_sections(
40
+ sections: sections,
41
+ section_objects: section_objects,
42
+ category_objects: category_objects
43
+ )
44
+
45
+ user_segments = zendesk.retrieve_all_user_segments
46
+ user_segment_objects = []
47
+ ZendeskGuideUserSegment.find_or_create_user_segments(user_segments: user_segments, user_segment_objects: user_segment_objects)
48
+
49
+ permission_groups = zendesk.retrieve_all_permission_groups
50
+ permission_group_objects = []
51
+ ZendeskGuidePermissionGroup.find_or_create_permission_groups(permission_groups: permission_groups, permission_group_objects: permission_group_objects)
52
+
53
+ articles = articles_sections_and_categories[:articles]
54
+ article_objects = []
55
+ ZendeskGuideArticle.find_or_create_articles(
56
+ articles: articles,
57
+ article_objects: article_objects,
58
+ section_objects: section_objects,
59
+ user_segment_objects: user_segment_objects,
60
+ permission_group_objects: permission_group_objects
61
+ )
62
+
63
+ article_attachments = zendesk.retrieve_all_article_attachments(articles: articles)
64
+ ZendeskGuideArticleAttachment.find_or_create_article_attachments(article_attachments: article_attachments, article_objects: article_objects)
65
+ rescue => e
66
+ raise e if Rails.env.development?
67
+ end
68
+ end
69
+
70
+ end
@@ -0,0 +1,95 @@
1
+ class ZendeskGuideArticle < ActiveRecord::Base
2
+ belongs_to :zendesk_guide_section
3
+ belongs_to :zendesk_guide_user_segment
4
+ belongs_to :zendesk_guide_permission_group
5
+
6
+ has_many :zendesk_guide_article_attachments
7
+
8
+ validates :title, presence: true
9
+ validates :locale, presence: true
10
+
11
+ def self.find_or_create_articles(options={})
12
+ articles = options[:articles]
13
+ article_objects = options[:article_objects]
14
+ section_objects = options[:section_objects]
15
+ user_segment_objects = options[:user_segment_objects]
16
+ permission_group_objects = options[:permission_group_objects]
17
+ allowed_attributes = [
18
+ :section_id,
19
+ :article_id,
20
+ :url,
21
+ :html_url,
22
+ :title,
23
+ :body,
24
+ :locale,
25
+ :source_locale,
26
+ :author_id,
27
+ :comments_disabled,
28
+ :outdated_locales,
29
+ :label_names,
30
+ :draft,
31
+ :promoted,
32
+ :position,
33
+ :vote_sum,
34
+ :vote_count,
35
+ :user_segment_id,
36
+ :permission_group_id,
37
+ :article_created_at,
38
+ :article_edited_at,
39
+ :article_updated_at
40
+ ]
41
+
42
+ articles.each do |a|
43
+ article_hash = a.clone
44
+
45
+ article_hash[:article_id] = article_hash["id"]
46
+ article_hash.delete("id")
47
+
48
+ article_hash[:article_created_at] = article_hash["created_at"]
49
+ article_hash.delete("created_at")
50
+
51
+ article_hash[:article_updated_at] = article_hash["updated_at"]
52
+ article_hash.delete("updated_at")
53
+
54
+ article_hash.symbolize_keys!
55
+
56
+ article_hash.each_key do |k|
57
+ article_hash.delete(k) if !allowed_attributes.include?(k)
58
+ end
59
+
60
+ article = ZendeskGuideArticle.where(article_id: article_hash[:article_id]).first
61
+ article.update(article_hash) if !article.nil?
62
+ article = ZendeskGuideArticle.create(article_hash) if article.nil?
63
+
64
+ changed = false
65
+
66
+ section_objects.each do |so|
67
+ is_correct_section = (article.section_id == so.section_id)
68
+ if is_correct_section
69
+ article.zendesk_guide_section = so
70
+ changed = true
71
+ end
72
+ end
73
+
74
+ user_segment_objects.each do |us|
75
+ is_correct_user_segment = (article.user_segment_id == us.user_segment_id)
76
+ if is_correct_user_segment
77
+ article.zendesk_guide_user_segment = us
78
+ changed = true
79
+ end
80
+ end
81
+
82
+ permission_group_objects.each do |pg|
83
+ is_correct_permission_group = (article.permission_group_id == pg.permission_group_id)
84
+ if is_correct_permission_group
85
+ article.zendesk_guide_permission_group = pg
86
+ changed = true
87
+ end
88
+ end
89
+
90
+ article.save if changed
91
+
92
+ article_objects << article
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,47 @@
1
+ class ZendeskGuideArticleAttachment < ActiveRecord::Base
2
+ belongs_to :zendesk_guide_article
3
+
4
+ def self.find_or_create_article_attachments(options={})
5
+ article_attachments = options[:article_attachments]
6
+ article_objects = options[:article_objects]
7
+ allowed_attributes = [
8
+ :article_id,
9
+ :article_attachment_id,
10
+ :url,
11
+ :file_name,
12
+ :content_url,
13
+ :size,
14
+ :inline,
15
+ :article_attachment_created_at,
16
+ :article_attachment_updated_at
17
+ ]
18
+
19
+ article_attachments.each do |aa|
20
+ article_attachment_hash = aa.clone
21
+
22
+ article_attachment_hash[:article_attachment_id] = article_attachment_hash["id"]
23
+ article_attachment_hash.delete("id")
24
+
25
+ article_attachment_hash[:article_attachment_created_at] = article_attachment_hash["created_at"]
26
+ article_attachment_hash.delete("created_at")
27
+
28
+ article_attachment_hash[:article_attachment_updated_at] = article_attachment_hash["updated_at"]
29
+ article_attachment_hash.delete("updated_at")
30
+
31
+ article_attachment_hash.symbolize_keys!
32
+
33
+ article_attachment = ZendeskGuideArticleAttachment.where(article_attachment_id: article_attachment_hash[:article_attachment_id]).first
34
+ article_attachment.update(article_attachment_hash) if !article_attachment.nil?
35
+ article_attachment = ZendeskGuideArticleAttachment.create(article_attachment_hash) if article_attachment.nil?
36
+
37
+ article_objects.each do |a|
38
+ is_correct_article = (article_attachment.article_id == a.article_id)
39
+ if is_correct_article
40
+ article_attachment.zendesk_guide_article = co
41
+ article_attachment.save
42
+ break
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,51 @@
1
+ class ZendeskGuideCategory < ActiveRecord::Base
2
+ has_many :zendesk_guide_sections
3
+
4
+ validates :name, presence: true
5
+ validates :locale, presence: true
6
+
7
+ def self.find_or_create_categories(options={})
8
+ categories = options[:categories]
9
+ category_objects = options[:category_objects]
10
+
11
+ allowed_attributes = [
12
+ :category_id,
13
+ :name,
14
+ :description,
15
+ :locale,
16
+ :source_locale,
17
+ :url,
18
+ :html_url,
19
+ :outdated,
20
+ :position,
21
+ :category_created_at,
22
+ :category_updated_at
23
+ ]
24
+
25
+ categories.each do |c|
26
+ category_hash = c.clone
27
+
28
+ category_hash[:category_id] = category_hash["id"]
29
+ category_hash.delete("id")
30
+
31
+ category_hash[:category_created_at] = category_hash["created_at"]
32
+ category_hash.delete("created_at")
33
+
34
+ category_hash[:category_updated_at] = category_hash["updated_at"]
35
+ category_hash.delete("updated_at")
36
+
37
+ category_hash.symbolize_keys!
38
+
39
+ category_hash.each_key do |k|
40
+ category_hash.delete(k) if !allowed_attributes.include?(k)
41
+ end
42
+
43
+ category = ZendeskGuideCategory.where(category_id: category_hash[:category_id]).first
44
+ category.update(category_hash) if !category.nil?
45
+ category = ZendeskGuideCategory.create(category_hash) if category.nil?
46
+
47
+ category_objects << category
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,42 @@
1
+ class ZendeskGuidePermissionGroup < ActiveRecord::Base
2
+ has_many :zendesk_guide_articles
3
+
4
+ def self.find_or_create_permission_groups(options={})
5
+ permission_groups = options[:permission_groups]
6
+ permission_group_objects = options[:permission_group_objects]
7
+ allowed_attributes = [
8
+ :permission_group_id,
9
+ :name,
10
+ :edit,
11
+ :publish,
12
+ :permission_group_created_at,
13
+ :permission_group_updated_at,
14
+ :built_in
15
+ ]
16
+
17
+ permission_groups.each do |p|
18
+ permission_group_hash = p.clone
19
+
20
+ permission_group_hash[:permission_group_id] = permission_group_hash["id"]
21
+ permission_group_hash.delete("id")
22
+
23
+ permission_group_hash[:permission_group_created_at] = permission_group_hash["created_at"]
24
+ permission_group_hash.delete("created_at")
25
+
26
+ permission_group_hash[:permission_group_updated_at] = permission_group_hash["updated_at"]
27
+ permission_group_hash.delete("updated_at")
28
+
29
+ permission_group_hash.symbolize_keys!
30
+
31
+ permission_group_hash.each_key do |k|
32
+ permission_group_hash.delete(k) if !allowed_attributes.include?(k)
33
+ end
34
+
35
+ permission_group = ZendeskGuidePermissionGroup.where(permission_group_id: permission_group_hash[:permission_group_id]).first
36
+ permission_group.update(permission_group_hash) if !permission_group.nil?
37
+ permission_group = ZendeskGuidePermissionGroup.create(permission_group_hash) if permission_group.nil?
38
+
39
+ permission_group_objects << permission_group
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,62 @@
1
+ class ZendeskGuideSection < ActiveRecord::Base
2
+ belongs_to :zendesk_guide_category
3
+ has_many :zendesk_guide_articles
4
+
5
+ validates :name, presence: true
6
+ validates :locale, presence: true
7
+
8
+ def self.find_or_create_sections(options={})
9
+ sections = options[:sections]
10
+ section_objects = options[:section_objects]
11
+ category_objects = options[:category_objects]
12
+
13
+ allowed_attributes = [
14
+ :category_id,
15
+ :section_id,
16
+ :name,
17
+ :description,
18
+ :locale,
19
+ :source_locale,
20
+ :url,
21
+ :html_url,
22
+ :outdated,
23
+ :position,
24
+ :section_created_at,
25
+ :section_updated_at
26
+ ]
27
+
28
+ sections.each do |s|
29
+ section_hash = s.clone
30
+
31
+ section_hash[:section_id] = section_hash["id"]
32
+ section_hash.delete("id")
33
+
34
+ section_hash[:section_created_at] = section_hash["created_at"]
35
+ section_hash.delete("created_at")
36
+
37
+ section_hash[:section_updated_at] = section_hash["updated_at"]
38
+ section_hash.delete("updated_at")
39
+
40
+ section_hash.symbolize_keys!
41
+
42
+ section_hash.each_key do |k|
43
+ section_hash.delete(k) if !allowed_attributes.include?(k)
44
+ end
45
+
46
+ section = ZendeskGuideSection.where(section_id: section_hash[:section_id]).first
47
+ section.update(section_hash) if !section.nil?
48
+ section = ZendeskGuideSection.create(section_hash) if section.nil?
49
+
50
+ category_objects.each do |co|
51
+ is_correct_category = (section.category_id == co.category_id)
52
+ if is_correct_category
53
+ section.zendesk_guide_category = co
54
+ section.save
55
+ break
56
+ end
57
+ end
58
+
59
+ section_objects << section
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,43 @@
1
+ class ZendeskGuideUserSegment < ActiveRecord::Base
2
+ has_many :zendesk_guide_articles
3
+
4
+ def self.find_or_create_user_segments(options={})
5
+ user_segments = options[:user_segments]
6
+ user_segment_objects = options[:user_segment_objects]
7
+ allowed_attributes = [
8
+ :user_segment_id,
9
+ :name,
10
+ :user_type,
11
+ :group_ids,
12
+ :organization_ids,
13
+ :tags,
14
+ :user_segment_created_at,
15
+ :user_segment_updated_at
16
+ ]
17
+
18
+ user_segments.each do |s|
19
+ user_segment_hash = s.clone
20
+
21
+ user_segment_hash[:user_segment_id] = user_segment_hash["id"]
22
+ user_segment_hash.delete("id")
23
+
24
+ user_segment_hash[:user_segment_created_at] = user_segment_hash["created_at"]
25
+ user_segment_hash.delete("created_at")
26
+
27
+ user_segment_hash[:user_segment_updated_at] = user_segment_hash["updated_at"]
28
+ user_segment_hash.delete("updated_at")
29
+
30
+ user_segment_hash.symbolize_keys!
31
+
32
+ user_segment_hash.each_key do |k|
33
+ user_segment_hash.delete(k) if !allowed_attributes.include?(k)
34
+ end
35
+
36
+ user_segment = ZendeskGuideUserSegment.where(user_segment_id: user_segment_hash[:user_segment_id]).first
37
+ user_segment.update(user_segment_hash) if !user_segment.nil?
38
+ user_segment = ZendeskGuideUserSegment.create(user_segment_hash) if user_segment.nil?
39
+
40
+ user_segment_objects << user_segment
41
+ end
42
+ end
43
+ end
@@ -1,8 +1,8 @@
1
1
  module Guidepost
2
2
  module Provider
3
3
  class Zendesk
4
- attr_accessor :subdomain
5
- attr_accessor :project_name
4
+ attr_reader :subdomain
5
+ attr_reader :project_name
6
6
 
7
7
  def initialize(options={})
8
8
  @subdomain = options[:subdomain]
@@ -17,31 +17,112 @@ module Guidepost
17
17
  @password = ENV["#{@project_name}_GUIDEPOST_ZENDESK_PASSWORD_TOKEN"]
18
18
  end
19
19
 
20
- def backup_all_articles
20
+ def backup_all_articles(options={})
21
21
  # Get all articles (with pagination)
22
- articles = self.retrieve_all_articles
22
+ sideload = options[:sideload] || false
23
+ articles = self.retrieve_all_articles(sideload: sideload)
23
24
 
24
25
  # Upload to S3
25
26
  timestamp = Time.now.strftime('%Y%m%d%H%M%S')
26
- @storage.upload_file(path: "zendesk/article_backups/#{timestamp}.json", string_content: articles.to_json)
27
+
28
+ filename = "#{timestamp}"
29
+ filename += "_with_sideload" if sideload
30
+ @storage.upload_file(path: "zendesk/article_backups/#{filename}.json", string_content: articles.to_json)
27
31
 
28
32
  articles.count
29
33
  end
30
34
 
31
- def retrieve_all_articles
32
- articles = []
35
+ def retrieve_all_articles(options={})
36
+ sideload = options[:sideload] || false
33
37
  page_next = nil
34
- while true
35
- page_articles, page_next = self.retrieve_articles(page_next)
36
- break if page_articles.nil? || page_articles.empty?
37
- articles += page_articles
38
- break if page_next.nil?
38
+ articles = []
39
+ article_attachments = nil
40
+
41
+ if !sideload
42
+ while true
43
+ page_articles, page_next = self.retrieve_articles(url: page_next)
44
+ break if page_articles.nil? || page_articles.empty?
45
+ articles += page_articles
46
+ break if page_next.nil?
47
+ end
48
+
49
+ article_attachments = self.retrieve_all_article_attachments(articles: articles)
50
+
51
+ return {
52
+ articles: articles,
53
+ article_count: articles.count,
54
+ article_attachments: article_attachments,
55
+ article_attachment_count: article_attachments.count
56
+ }
57
+ else
58
+ sections = []
59
+ categories = []
60
+
61
+ section_urls = Hash.new
62
+ category_urls = Hash.new
63
+
64
+ while true
65
+ page, page_next = self.retrieve_articles(url: page_next, sideload: true)
66
+
67
+ articles_from_page = page["articles"]
68
+ sections_from_page = page["sections"]
69
+ categories_from_page = page["categories"]
70
+
71
+ no_more_articles = articles_from_page.nil? || articles_from_page.empty?
72
+ no_more_sections = sections_from_page.nil? || sections_from_page.empty?
73
+ no_more_categories = categories_from_page.nil? || categories_from_page.empty?
74
+
75
+ break if no_more_articles && no_more_sections && no_more_categories
76
+
77
+ articles += articles_from_page
78
+
79
+ sections_from_page.each do |s|
80
+ url = s["url"]
81
+ if !section_urls.has_key?(url)
82
+ section_urls[url] = 1
83
+ else
84
+ section_urls[url] += 1
85
+ end
86
+ sections << s if section_urls[url] == 1
87
+ end
88
+
89
+ categories_from_page.each do |c|
90
+ url = c["url"]
91
+ if !category_urls.has_key?(url)
92
+ category_urls[url] = 1
93
+ else
94
+ category_urls[url] += 1
95
+ end
96
+ categories << c if category_urls[url] == 1
97
+ end
98
+
99
+ break if page_next.nil?
100
+ end
101
+
102
+ article_attachments = self.retrieve_all_article_attachments(articles: articles)
103
+
104
+ return {
105
+ categories: categories,
106
+ category_count: categories.count,
107
+ sections: sections,
108
+ section_count: sections.count,
109
+ articles: articles,
110
+ article_count: articles.count,
111
+ article_attachments: article_attachments,
112
+ article_attachment_count: article_attachments.count
113
+ }
39
114
  end
40
- articles
41
115
  end
42
116
 
43
- def retrieve_articles(url)
44
- url = "#{self.base_api_url}/help_center/articles.json?include=translations&per_page=25&page=1" if url.nil?
117
+ def retrieve_articles(options={})
118
+ url = options[:url]
119
+ sideload = options[:sideload] || false
120
+
121
+ if !sideload
122
+ url = "#{self.base_api_url}/help_center/articles.json?per_page=25&page=1" if url.nil?
123
+ else
124
+ url = "#{self.base_api_url}/help_center/articles.json?include=sections,categories&per_page=25&page=1" if url.nil?
125
+ end
45
126
 
46
127
  uri = URI.parse(url)
47
128
 
@@ -56,7 +137,118 @@ module Guidepost
56
137
  body = response.body.force_encoding("UTF-8")
57
138
 
58
139
  j_body = JSON.parse(body)
59
- return j_body['articles'], j_body['next_page']
140
+
141
+ if !sideload
142
+ return j_body['articles'], j_body['next_page']
143
+ else
144
+ return j_body, j_body['next_page']
145
+ end
146
+ end
147
+
148
+ def retrieve_all_user_segments(options={})
149
+ user_segments = []
150
+ next_page = nil
151
+
152
+ while true
153
+ segments, next_page = self.retrieve_user_segments(url: next_page)
154
+ break if segments.nil? || segments.empty?
155
+ user_segments += segments
156
+ break if next_page.nil?
157
+ end
158
+
159
+ user_segments
160
+ end
161
+
162
+ def retrieve_user_segments(options={})
163
+ url = options[:url]
164
+ url = "#{self.base_api_url}/help_center/user_segments.json?per_page=25&page=1" if url.nil?
165
+ uri = URI.parse(url)
166
+
167
+ http = Net::HTTP.new(uri.host, uri.port)
168
+ http.use_ssl = true
169
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
170
+
171
+ request = Net::HTTP::Get.new(uri.request_uri)
172
+ request.basic_auth(@email, @password)
173
+ response = http.request(request)
174
+
175
+ body = response.body.force_encoding("UTF-8")
176
+
177
+ j_body = JSON.parse(body)
178
+
179
+ return j_body["user_segments"], j_body['next_page']
180
+ end
181
+
182
+ def retrieve_all_permission_groups(options={})
183
+ permission_groups = []
184
+ next_page = nil
185
+
186
+ while true
187
+ groups, next_page = self.retrieve_permission_groups(url: next_page)
188
+ break if groups.nil? || groups.empty?
189
+ permission_groups += groups
190
+ break if next_page.nil?
191
+ end
192
+
193
+ permission_groups
194
+ end
195
+
196
+ def retrieve_permission_groups(options={})
197
+ url = options[:url]
198
+ url = "#{self.base_api_url}/guide/permission_groups.json?per_page=25&page=1" if url.nil?
199
+ uri = URI.parse(url)
200
+
201
+ http = Net::HTTP.new(uri.host, uri.port)
202
+ http.use_ssl = true
203
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
204
+
205
+ request = Net::HTTP::Get.new(uri.request_uri)
206
+ request.basic_auth(@email, @password)
207
+ response = http.request(request)
208
+
209
+ body = response.body.force_encoding("UTF-8")
210
+
211
+ j_body = JSON.parse(body)
212
+
213
+ return j_body["permission_groups"], j_body['next_page']
214
+ end
215
+
216
+ def retrieve_all_article_attachments(options={})
217
+ article_attachments = []
218
+ next_page = nil
219
+
220
+ articles = options[:articles]
221
+ articles.each do |article|
222
+ while true
223
+ attachments, next_page = self.retrieve_article_attachments(for_article: article)
224
+ break if attachments.nil? || attachments.empty?
225
+ article_attachments += attachments
226
+ break if next_page.nil?
227
+ end
228
+ end
229
+
230
+ article_attachments
231
+ end
232
+
233
+ def retrieve_article_attachments(options={})
234
+ article = options[:for_article]
235
+
236
+ url = "#{self.base_api_url}/help_center/articles/#{article["id"]}/attachments.json?per_page=25&page=1" if url.nil?
237
+ uri = URI.parse(url)
238
+
239
+ http = Net::HTTP.new(uri.host, uri.port)
240
+ http.use_ssl = true
241
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
242
+
243
+ request = Net::HTTP::Get.new(uri.request_uri)
244
+ request.basic_auth(@email, @password)
245
+ response = http.request(request)
246
+
247
+ body = response.body.force_encoding("UTF-8")
248
+
249
+ j_body = JSON.parse(body)
250
+
251
+ return j_body["article_attachments"], j_body["next_page"]
60
252
  end
61
253
 
62
254
  def base_api_url
@@ -1,7 +1,7 @@
1
1
  module Guidepost
2
2
  module Storage
3
3
  class S3
4
- attr_accessor :project_name
4
+ attr_reader :project_name
5
5
 
6
6
  def initialize(options={})
7
7
  @project_name = options[:project_name]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: guidepost
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kiren Srinivasan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-06 00:00:00.000000000 Z
11
+ date: 2019-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -24,18 +24,28 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
- description: Harness your knowledge base in your Ruby applications
28
- email: kiren.srinivasan@holbertonschool.com
27
+ description: Harness your knowledge base in your Rails applications
28
+ email: srinitude@gmail.com
29
29
  executables: []
30
30
  extensions: []
31
31
  extra_rdoc_files: []
32
32
  files:
33
33
  - LICENSE
34
34
  - README.md
35
+ - lib/generators/guidepost/migrate_generator.rb
36
+ - lib/generators/guidepost/models_generator.rb
37
+ - lib/generators/guidepost/templates/migrations.rb
38
+ - lib/generators/guidepost/templates/zendesk_guide.rake
39
+ - lib/generators/guidepost/templates/zendesk_guide_article.rb
40
+ - lib/generators/guidepost/templates/zendesk_guide_article_attachment.rb
41
+ - lib/generators/guidepost/templates/zendesk_guide_category.rb
42
+ - lib/generators/guidepost/templates/zendesk_guide_permission_group.rb
43
+ - lib/generators/guidepost/templates/zendesk_guide_section.rb
44
+ - lib/generators/guidepost/templates/zendesk_guide_user_segment.rb
35
45
  - lib/guidepost.rb
36
46
  - lib/guidepost/provider/zendesk.rb
37
47
  - lib/guidepost/storage/s3.rb
38
- homepage:
48
+ homepage: https://github.com/srinitude/guidepost
39
49
  licenses:
40
50
  - MIT
41
51
  metadata: {}
@@ -58,5 +68,5 @@ rubyforge_project:
58
68
  rubygems_version: 2.7.6
59
69
  signing_key:
60
70
  specification_version: 4
61
- summary: Harness your knowledge base in your Ruby applications
71
+ summary: Harness your knowledge base in your Rails applications
62
72
  test_files: []