discourse_dev 0.0.7 → 0.2.1

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/README.md +40 -4
  4. data/auth/app/views/fake_discourse_connect/form.html.erb +120 -0
  5. data/auth/plugin.rb +219 -0
  6. data/avatars/03F55412-DE8A-4F83-AAA6-D67EE5CE48DA-200w.jpeg +0 -0
  7. data/avatars/1C4EEDC2-FE9C-40B3-A2C9-A038873EE692-200w.jpeg +0 -0
  8. data/avatars/26CFEFB3-21C8-49FC-8C19-8E6A62B6D2E0-200w.jpeg +0 -0
  9. data/avatars/282A12CA-E0D7-4011-8BDD-1FAFAAB035F7-200w.jpeg +0 -0
  10. data/avatars/2DDDE973-40EC-4004-ABC0-73FD4CD6D042-200w.jpeg +0 -0
  11. data/avatars/344CFC24-61FB-426C-B3D1-CAD5BCBD3209-200w.jpeg +0 -0
  12. data/avatars/852EC6E1-347C-4187-9D42-DF264CCF17BF-200w.jpeg +0 -0
  13. data/avatars/A7299C8E-CEFC-47D9-939A-3C8CA0EA4D13-200w.jpeg +0 -0
  14. data/avatars/AEF44435-B547-4B84-A2AE-887DFAEE6DDF-200w.jpeg +0 -0
  15. data/avatars/B3CF5288-34B0-4A5E-9877-5965522529D6-200w.jpeg +0 -0
  16. data/avatars/BA0CB1F2-8C79-4376-B13B-DD5FB8772537-200w.jpeg +0 -0
  17. data/avatars/E0B4CAB3-F491-4322-BEF2-208B46748D4A-200w.jpeg +0 -0
  18. data/avatars/FBEBF655-4886-455A-A4A4-D62B77DD419B-200w.jpeg +0 -0
  19. data/config/dev.yml +38 -0
  20. data/config/locales/client.en.yml +6 -0
  21. data/{lib/faker/locales/en.yml → config/locales/faker.en.yml} +0 -0
  22. data/discourse_dev.gemspec +1 -0
  23. data/lib/discourse_dev.rb +49 -4
  24. data/lib/discourse_dev/category.rb +3 -3
  25. data/lib/discourse_dev/config.rb +101 -29
  26. data/lib/discourse_dev/group.rb +4 -5
  27. data/lib/discourse_dev/post.rb +35 -16
  28. data/lib/discourse_dev/record.rb +13 -11
  29. data/lib/discourse_dev/tag.rb +14 -2
  30. data/lib/discourse_dev/tasks/dev.rake +6 -2
  31. data/lib/discourse_dev/topic.rb +48 -11
  32. data/lib/discourse_dev/user.rb +58 -7
  33. data/lib/discourse_dev/version.rb +1 -1
  34. data/lib/faker/discourse_markdown.rb +96 -0
  35. metadata +36 -4
  36. data/lib/discourse_dev/config.yml +0 -4
@@ -7,8 +7,20 @@ require 'faker'
7
7
  module DiscourseDev
8
8
  class Tag < Record
9
9
 
10
- def initialize(count = DEFAULT_COUNT)
11
- super(::Tag, count)
10
+ def initialize
11
+ super(::Tag, DiscourseDev.config.tag[:count])
12
+ end
13
+
14
+ def create!
15
+ super
16
+ rescue ActiveRecord::RecordInvalid => e
17
+ # If the name is taken, try again
18
+ retry
19
+ end
20
+
21
+ def populate!
22
+ return unless SiteSetting.tagging_enabled
23
+ super
12
24
  end
13
25
 
14
26
  def data
@@ -4,6 +4,9 @@ def check_environment!
4
4
  if !Rails.env.development?
5
5
  raise "Database commands are only supported in development environment"
6
6
  end
7
+
8
+ ENV['SKIP_TEST_DATABASE'] = "1"
9
+ ENV['SKIP_MULTISITE'] = "1"
7
10
  end
8
11
 
9
12
  desc 'Run db:migrate:reset task and populate sample content for development environment'
@@ -17,11 +20,12 @@ end
17
20
 
18
21
  desc 'Initialize development environment'
19
22
  task 'dev:config' => ['db:load_config'] do |_, args|
20
- DiscourseDev::Config.new.update!
23
+ DiscourseDev.config.update!
21
24
  end
22
25
 
23
26
  desc 'Populate sample content for development environment'
24
27
  task 'dev:populate' => ['db:load_config'] do |_, args|
28
+ system("redis-cli flushall")
25
29
  Rake::Task['groups:populate'].invoke
26
30
  Rake::Task['users:populate'].invoke
27
31
  Rake::Task['categories:populate'].invoke
@@ -38,6 +42,6 @@ task 'dev:repopulate' => ['db:load_config'] do |_, args|
38
42
  if (answer == "" || answer.downcase == 'y')
39
43
  Rake::Task['dev:reset'].invoke
40
44
  else
41
- puts "You can run `dev:reset` rake task to do this repopulate action anytime."
45
+ puts "You can run `bin/rails dev:reset` to repopulate anytime."
42
46
  end
43
47
  end
@@ -6,33 +6,58 @@ require 'faker'
6
6
  module DiscourseDev
7
7
  class Topic < Record
8
8
 
9
- def initialize(count = DEFAULT_COUNT)
10
- super(::Topic, count)
9
+ def initialize
10
+ @settings = DiscourseDev.config.topic
11
+ super(::Topic, @settings[:count])
11
12
  end
12
13
 
13
14
  def data
15
+ max_views = 0
16
+
17
+ case Faker::Number.between(from: 0, to: 5)
18
+ when 0
19
+ max_views = 10
20
+ when 1
21
+ max_views = 100
22
+ when 2
23
+ max_views = SiteSetting.topic_views_heat_low
24
+ when 3
25
+ max_views = SiteSetting.topic_views_heat_medium
26
+ when 4
27
+ max_views = SiteSetting.topic_views_heat_high
28
+ when 5
29
+ max_views = SiteSetting.topic_views_heat_high + SiteSetting.topic_views_heat_medium
30
+ end
31
+
14
32
  {
15
33
  title: title[0, SiteSetting.max_topic_title_length],
16
- raw: Faker::Markdown.sandwich(sentences: 5),
34
+ raw: Faker::DiscourseMarkdown.sandwich(sentences: 5),
17
35
  category: @category.id,
36
+ created_at: Faker::Time.between(from: DiscourseDev.config.start_date, to: DateTime.now),
18
37
  tags: tags,
19
- topic_opts: { custom_fields: { dev_sample: true } },
38
+ topic_opts: {
39
+ import_mode: true,
40
+ views: Faker::Number.between(from: 1, to: max_views),
41
+ custom_fields: { dev_sample: true }
42
+ },
20
43
  skip_validations: true
21
44
  }
22
45
  end
23
46
 
24
47
  def title
25
- if index <= I18n.t("faker.discourse.topics").count
48
+ if current_count < I18n.t("faker.discourse.topics").count
26
49
  Faker::Discourse.unique.topic
27
50
  else
28
- Faker::Lorem.unique.sentence(word_count: 3, supplemental: true, random_words_to_add: 4).chomp(".")
51
+ Faker::Lorem.unique.sentence(word_count: 5, supplemental: true, random_words_to_add: 4).chomp(".")
29
52
  end
30
53
  end
31
54
 
32
55
  def tags
56
+ return unless SiteSetting.tagging_enabled
57
+
33
58
  @tags = []
34
59
 
35
- Faker::Number.between(from: 0, to: 3).times do
60
+ Faker::Number.between(from: @settings.dig(:tags, :min), to: @settings.dig(:tags, :max)).times do
36
61
  @tags << Faker::Discourse.tag
37
62
  end
38
63
 
@@ -41,18 +66,24 @@ module DiscourseDev
41
66
 
42
67
  def create!
43
68
  @category = Category.random
44
- topic = data
69
+ user = self.user
70
+ topic = Faker::DiscourseMarkdown.with_user(user.id) { data }
45
71
  post = PostCreator.new(user, topic).create!
46
72
 
47
- if topic[:title] == "Coolest thing you have seen today"
48
- reply_count = 99
73
+ if override = @settings.dig(:replies, :overrides).find { |o| o[:title] == topic[:title] }
74
+ reply_count = override[:count]
49
75
  else
50
- reply_count = Faker::Number.between(from: 0, to: 12)
76
+ reply_count = Faker::Number.between(from: @settings.dig(:replies, :min), to: @settings.dig(:replies, :max))
51
77
  end
52
78
 
53
79
  Post.new(post.topic, reply_count).populate!
54
80
  end
55
81
 
82
+ def populate!
83
+ super
84
+ delete_unwanted_sidekiq_jobs
85
+ end
86
+
56
87
  def user
57
88
  return User.random if @category.groups.blank?
58
89
 
@@ -67,5 +98,11 @@ module DiscourseDev
67
98
  category_definition_topic_ids = ::Category.pluck(:topic_id)
68
99
  ::Topic.where(archetype: :regular).where.not(id: category_definition_topic_ids).count
69
100
  end
101
+
102
+ def delete_unwanted_sidekiq_jobs
103
+ Sidekiq::ScheduledSet.new.each do |job|
104
+ job.delete if job.item["class"] == "Jobs::UserEmail"
105
+ end
106
+ end
70
107
  end
71
108
  end
@@ -6,16 +6,22 @@ require 'faker'
6
6
 
7
7
  module DiscourseDev
8
8
  class User < Record
9
+ attr_reader :images
9
10
 
10
- def initialize(count = DEFAULT_COUNT)
11
- super(::User, count)
11
+ def initialize
12
+ super(::User, DiscourseDev.config.user[:count])
13
+
14
+ # Using the stock avatar images from https://tinyfac.es
15
+ # Tiny Faces is a free crowd-sourced avatar gallery
16
+ @images = Dir[File.join(__dir__, '..', '..', 'avatars', '*.*')]
12
17
  end
13
18
 
14
19
  def data
15
20
  name = Faker::Name.unique.name
16
- email = Faker::Internet.unique.email(name: name)
17
- username = Faker::Internet.unique.username(specifier: name)[0, SiteSetting.max_username_length]
18
- username_lower = username.downcase
21
+ email = Faker::Internet.unique.email(name: name, domain: "faker.invalid")
22
+ username = Faker::Internet.unique.username(specifier: ::User.username_length)
23
+ username = UserNameSuggester.suggest(username)
24
+ username_lower = ::User.normalize_username(username)
19
25
 
20
26
  {
21
27
  name: name,
@@ -23,16 +29,18 @@ module DiscourseDev
23
29
  username: username,
24
30
  username_lower: username_lower,
25
31
  moderator: Faker::Boolean.boolean(true_ratio: 0.1),
26
- trust_level: Faker::Number.between(from: 1, to: 4)
32
+ trust_level: Faker::Number.between(from: 1, to: 4),
33
+ created_at: Faker::Time.between(from: DiscourseDev.config.start_date, to: DateTime.now),
27
34
  }
28
35
  end
29
36
 
30
37
  def create!
31
38
  super do |user|
32
39
  user.activate
40
+ set_random_avatar(user)
33
41
  Faker::Number.between(from: 0, to: 2).times do
34
42
  group = Group.random
35
-
43
+
36
44
  group.add(user)
37
45
  end
38
46
  end
@@ -41,5 +49,48 @@ module DiscourseDev
41
49
  def self.random
42
50
  super(::User)
43
51
  end
52
+
53
+ def set_random_avatar(user)
54
+ return if images.blank?
55
+ return unless Faker::Boolean.boolean
56
+
57
+ avatar_index = Faker::Number.between(from: 0, to: images.count - 1)
58
+ avatar_path = images[avatar_index]
59
+ create_avatar(user, avatar_path)
60
+ @images.delete_at(avatar_index)
61
+ end
62
+
63
+ def create_avatar(user, avatar_path)
64
+ tempfile = copy_to_tempfile(avatar_path)
65
+ filename = "avatar#{File.extname(avatar_path)}"
66
+ upload = UploadCreator.new(tempfile, filename, type: "avatar").create_for(user.id)
67
+
68
+ if upload.present? && upload.persisted?
69
+ user.create_user_avatar
70
+ user.user_avatar.update(custom_upload_id: upload.id)
71
+ user.update(uploaded_avatar_id: upload.id)
72
+ else
73
+ STDERR.puts "Failed to upload avatar for user #{user.username}: #{avatar_path}"
74
+ STDERR.puts upload.errors.inspect if upload
75
+ end
76
+ rescue
77
+ STDERR.puts "Failed to create avatar for user #{user.username}: #{avatar_path}"
78
+ ensure
79
+ tempfile.close! if tempfile
80
+ end
81
+
82
+ private
83
+
84
+ def copy_to_tempfile(source_path)
85
+ extension = File.extname(source_path)
86
+ tmp = Tempfile.new(['discourse-upload', extension])
87
+
88
+ File.open(source_path) do |source_stream|
89
+ IO.copy_stream(source_stream, tmp)
90
+ end
91
+
92
+ tmp.rewind
93
+ tmp
94
+ end
44
95
  end
45
96
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DiscourseDev
4
- VERSION = "0.0.7"
4
+ VERSION = "0.2.1"
5
5
  end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faker'
4
+ require 'net/http'
5
+ require 'json'
6
+
7
+ module Faker
8
+ class DiscourseMarkdown < Markdown
9
+ class << self
10
+ attr_writer(:user_id)
11
+
12
+ def user_id
13
+ @user_id || ::Discourse::SYSTEM_USER_ID
14
+ end
15
+
16
+ def with_user(user_id)
17
+ current_user_id = self.user_id
18
+ self.user_id = user_id
19
+ begin
20
+ yield
21
+ ensure
22
+ self.user_id = current_user_id
23
+ end
24
+ end
25
+
26
+ def image
27
+ image = next_image
28
+ image_file = load_image(image)
29
+
30
+ upload = ::UploadCreator.new(
31
+ image_file,
32
+ image[:filename],
33
+ origin: image[:url]
34
+ ).create_for(user_id)
35
+
36
+ ::UploadMarkdown.new(upload).to_markdown if upload.present? && upload.persisted?
37
+ rescue => e
38
+ STDERR.puts e
39
+ STDERR.puts e.backtrace.join("\n")
40
+ end
41
+
42
+ private
43
+
44
+ def next_image
45
+ if @images.blank?
46
+ if @stop_loading_images
47
+ @images = @all_images.dup
48
+ else
49
+ @next_page = (@next_page || 0) + 1
50
+ url = URI("https://picsum.photos/v2/list?page=#{@next_page}&limit=50")
51
+ response = Net::HTTP.get(url)
52
+ json = JSON.parse(response)
53
+
54
+ if json.blank?
55
+ @stop_loading_images = true
56
+ @images = @all_images.dup
57
+ else
58
+ @images = json.sort_by { |image| image["id"] }
59
+ @all_images = (@all_images || []).concat(@images)
60
+ end
61
+ end
62
+ end
63
+
64
+ image = @images.pop
65
+ { filename: "#{image['id']}.jpg", url: "#{image['download_url']}.jpg" }
66
+ end
67
+
68
+ def image_cache_dir
69
+ @image_cache_dir ||= ::File.join(Rails.root, "tmp", "discourse_dev", "images")
70
+ end
71
+
72
+ def load_image(image)
73
+ cache_path = ::File.join(image_cache_dir, image[:filename])
74
+
75
+ if !::File.exists?(cache_path)
76
+ FileUtils.mkdir_p(image_cache_dir)
77
+ temp_file = ::FileHelper.download(
78
+ image[:url],
79
+ max_file_size: [SiteSetting.max_image_size_kb.kilobytes, 10.megabytes].max,
80
+ tmp_file_name: "image",
81
+ follow_redirect: true
82
+ )
83
+ FileUtils.cp(temp_file, cache_path)
84
+ end
85
+
86
+ ::File.open(cache_path)
87
+ end
88
+
89
+ def available_methods
90
+ methods = super
91
+ methods << :image if ::DiscourseDev.config.post[:include_images]
92
+ methods
93
+ end
94
+ end
95
+ end
96
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discourse_dev
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vinoth Kannan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-07 00:00:00.000000000 Z
11
+ date: 2021-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faker
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 12.3.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop-discourse
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: Rake helper tasks for Discourse developers
56
70
  email:
57
71
  - svkn.87@gmail.com
@@ -61,16 +75,34 @@ extra_rdoc_files: []
61
75
  files:
62
76
  - ".github/workflows/gem-push.yml"
63
77
  - ".gitignore"
78
+ - ".rubocop.yml"
64
79
  - Gemfile
65
80
  - LICENSE.txt
66
81
  - README.md
67
82
  - Rakefile
83
+ - auth/app/views/fake_discourse_connect/form.html.erb
84
+ - auth/plugin.rb
85
+ - avatars/03F55412-DE8A-4F83-AAA6-D67EE5CE48DA-200w.jpeg
86
+ - avatars/1C4EEDC2-FE9C-40B3-A2C9-A038873EE692-200w.jpeg
87
+ - avatars/26CFEFB3-21C8-49FC-8C19-8E6A62B6D2E0-200w.jpeg
88
+ - avatars/282A12CA-E0D7-4011-8BDD-1FAFAAB035F7-200w.jpeg
89
+ - avatars/2DDDE973-40EC-4004-ABC0-73FD4CD6D042-200w.jpeg
90
+ - avatars/344CFC24-61FB-426C-B3D1-CAD5BCBD3209-200w.jpeg
91
+ - avatars/852EC6E1-347C-4187-9D42-DF264CCF17BF-200w.jpeg
92
+ - avatars/A7299C8E-CEFC-47D9-939A-3C8CA0EA4D13-200w.jpeg
93
+ - avatars/AEF44435-B547-4B84-A2AE-887DFAEE6DDF-200w.jpeg
94
+ - avatars/B3CF5288-34B0-4A5E-9877-5965522529D6-200w.jpeg
95
+ - avatars/BA0CB1F2-8C79-4376-B13B-DD5FB8772537-200w.jpeg
96
+ - avatars/E0B4CAB3-F491-4322-BEF2-208B46748D4A-200w.jpeg
97
+ - avatars/FBEBF655-4886-455A-A4A4-D62B77DD419B-200w.jpeg
98
+ - config/dev.yml
99
+ - config/locales/client.en.yml
100
+ - config/locales/faker.en.yml
68
101
  - config/routes.rb
69
102
  - discourse_dev.gemspec
70
103
  - lib/discourse_dev.rb
71
104
  - lib/discourse_dev/category.rb
72
105
  - lib/discourse_dev/config.rb
73
- - lib/discourse_dev/config.yml
74
106
  - lib/discourse_dev/engine.rb
75
107
  - lib/discourse_dev/group.rb
76
108
  - lib/discourse_dev/post.rb
@@ -83,7 +115,7 @@ files:
83
115
  - lib/discourse_dev/user.rb
84
116
  - lib/discourse_dev/version.rb
85
117
  - lib/faker/discourse.rb
86
- - lib/faker/locales/en.yml
118
+ - lib/faker/discourse_markdown.rb
87
119
  homepage: https://github.com/discourse/discourse_dev
88
120
  licenses:
89
121
  - MIT
@@ -1,4 +0,0 @@
1
- site_settings:
2
- tagging_enabled: true
3
- verbose_discourse_connect_logging: true
4
- seed: 1