rails-wiki 0.1.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 (93) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +55 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/javascripts/inject.js +34 -0
  6. data/app/assets/javascripts/wiki/application.js +13 -0
  7. data/app/assets/stylesheets/wiki/application.css +15 -0
  8. data/app/controllers/wiki/application_controller.rb +33 -0
  9. data/app/controllers/wiki/pages_controller.rb +80 -0
  10. data/app/helpers/wiki/application_helper.rb +4 -0
  11. data/app/helpers/wiki/wiki_helper.rb +8 -0
  12. data/app/models/wiki/attachment.rb +116 -0
  13. data/app/models/wiki/page.rb +213 -0
  14. data/app/models/wiki/wiki.rb +194 -0
  15. data/app/views/layouts/application.html.erb +14 -0
  16. data/app/views/layouts/wiki.html.erb +19 -0
  17. data/app/views/wiki/_change.erb +21 -0
  18. data/app/views/wiki/_search.erb +4 -0
  19. data/app/views/wiki/pages/edit.html.erb +69 -0
  20. data/app/views/wiki/pages/index.html.erb +16 -0
  21. data/app/views/wiki/pages/log.html.erb +29 -0
  22. data/app/views/wiki/pages/show.html.erb +50 -0
  23. data/config/initializers/wiki.rb +35 -0
  24. data/config/routes.rb +16 -0
  25. data/lib/frontmatter.rb +23 -0
  26. data/lib/markdown.rb +24 -0
  27. data/lib/rails-wiki.rb +18 -0
  28. data/lib/tasks/wiki_tasks.rake +4 -0
  29. data/lib/wiki/engine.rb +10 -0
  30. data/lib/wiki/version.rb +3 -0
  31. data/test/dummy/Rakefile +6 -0
  32. data/test/dummy/app/assets/javascripts/application.js +13 -0
  33. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  34. data/test/dummy/app/controllers/application_controller.rb +16 -0
  35. data/test/dummy/app/helpers/application_helper.rb +2 -0
  36. data/test/dummy/app/models/user.rb +11 -0
  37. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  38. data/test/dummy/bin/bundle +3 -0
  39. data/test/dummy/bin/rails +4 -0
  40. data/test/dummy/bin/rake +4 -0
  41. data/test/dummy/bin/setup +29 -0
  42. data/test/dummy/config.ru +4 -0
  43. data/test/dummy/config/application.rb +23 -0
  44. data/test/dummy/config/boot.rb +5 -0
  45. data/test/dummy/config/environment.rb +5 -0
  46. data/test/dummy/config/environments/development.rb +39 -0
  47. data/test/dummy/config/environments/production.rb +77 -0
  48. data/test/dummy/config/environments/test.rb +42 -0
  49. data/test/dummy/config/initializers/assets.rb +11 -0
  50. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  51. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  52. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  53. data/test/dummy/config/initializers/inflections.rb +16 -0
  54. data/test/dummy/config/initializers/mime_types.rb +4 -0
  55. data/test/dummy/config/initializers/session_store.rb +3 -0
  56. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  57. data/test/dummy/config/locales/en.yml +23 -0
  58. data/test/dummy/config/routes.rb +4 -0
  59. data/test/dummy/config/secrets.yml +22 -0
  60. data/test/dummy/db/wiki/test.md +1 -0
  61. data/test/dummy/db/wiki/test/brown-forward.jpg +0 -0
  62. data/test/dummy/log/development.log +1558 -0
  63. data/test/dummy/public/404.html +67 -0
  64. data/test/dummy/public/422.html +67 -0
  65. data/test/dummy/public/500.html +66 -0
  66. data/test/dummy/public/favicon.ico +0 -0
  67. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/20sgF5rnRshHxz-s4EBzqr6J28hCEioHDZq4UwSklVg.cache +0 -0
  68. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/2c3DnJIoxPn2b4vs5wqFWgOX0nJESf5SGAUi9N58_9o.cache +0 -0
  69. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/3CXqY8DyRTsJJYP9iYJaaQRmpXDbd-MFR1m4pug2GnQ.cache +1 -0
  70. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/3RqPYAE8n3lRHkprA7M3_eFnzLV5PF6FMwwk-fs_ieM.cache +1 -0
  71. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +2 -0
  72. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/BPtu96YPU5tNXsZRFA9WtMIergTFfHMuhAG3ON7DdJY.cache +0 -0
  73. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/D0X36t9hc6V_oaygIyRL41fwhkF3u9Lw12FETkPMVoc.cache +1 -0
  74. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/GtnQFUKxR1hZ540gdO9116uyLq4JfA-QB7ZsLJwvlj0.cache +1 -0
  75. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/HiLFBQupKg3TaAuqwWTIVzukgysleTkF1bjaEaIODS0.cache +1 -0
  76. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/JZuS80RuzB2Cuqgdj4m_cnDrAKe36_z_v5Ty_dPoIJ4.cache +3 -0
  77. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +3 -0
  78. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/X6P11z9IhRL9BK1a0t3QcW0nzXwZKzz50d35fpmMDbQ.cache +1 -0
  79. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/YzlRBEEf9MMtDMXOU1Dy6zoeRsaAZSXIUSZmXxVflT0.cache +0 -0
  80. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/h0IIenP5nZ0YCtFDIHLHyp9pvsOLSDEu6ATiy3gr5D0.cache +1 -0
  81. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/hOPmvE7Kf6eW1WQC0bUXD7G5V_zrmprQYp0Ovw03Cng.cache +1 -0
  82. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/hPk5G_BGOYjelHgOl4_2QEgvC6YnAVRQzTyN1dBvBAE.cache +0 -0
  83. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +3 -0
  84. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/hz0b1Jdsh_JFLZIiQe7zAkicSerKslNSllnkeXXp_04.cache +2 -0
  85. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/nAoWwNAloHngS8ny7fZE5G4uUShw8tjgvVMkDMvMkpg.cache +1 -0
  86. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +2 -0
  87. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/qZPgqsYHITlAKR9bPIGwt2SSzDuKpMUUkQrEZb2MkMg.cache +0 -0
  88. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/rG7CS4nu-OV8bgDR74JP3ukGDdcMYoC_w7V0TMphk04.cache +0 -0
  89. data/test/dummy/tmp/cache/assets/development/sprockets/v3.0/z-qEGw9bb3jqMEbMPC02VNSESIylpz0Pri2mSnoVNv8.cache +1 -0
  90. data/test/integration/navigation_test.rb +10 -0
  91. data/test/test_helper.rb +20 -0
  92. data/test/wiki_test.rb +7 -0
  93. metadata +256 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: aaa5b76e359711bd8dc4aa0e183906b335bce16d
4
+ data.tar.gz: f3c24e3ec96ae567912750f402331420e12ecb7a
5
+ SHA512:
6
+ metadata.gz: 82b49289f36a9d89d5df6ca1f4e740b9761c9c2fe32a0a745124e657a3738b68f9075f6f9c53ec966e34784773700486c527c9a5528dc59133ba6e00b31ff590
7
+ data.tar.gz: 7d859845c6c6f10347cdef24afca2658208e6a46e1b85a3b41effbd6b698f95f2e48ec807a695bb7ec06cbc903a01cad2d4704841ad5c351299d6080d803fa7f
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Hans Gerwitz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,55 @@
1
+ # Rails Wiki
2
+
3
+ A small Rails engine that provides a git-based Markdown wiki.
4
+
5
+ WARNING: this has been abstracted from a proprietary tool, and so is poorly documented and lacks a standalone test suite. It would be premature to include it as a blind dependency.
6
+
7
+ ## How it Works
8
+
9
+ Rails Wiki is based on [gollum-lib](https://github.com/gollum/gollum-lib). None of [Gollum](https://github.com/gollum/gollum/wiki)'s layout (e.g. sidebars, headers, footers) are implemented, and a many of the text filters (e.g. macros, code, diagrams) have been disabled. Also unlike Gollum, the hierarchy of pages is considered meaningful.
10
+
11
+ The storage structure will be familiar to users of Middleman or Jekyll. Each page is an `.md` file with YAML frontmatter for metadata. Other files are treated as attachments to the page associated with their containing directory.
12
+
13
+ All storage is via a local Git repository. Optionally, a remote can be specified and changes will be pushed to it.
14
+
15
+ _TODO: review and document remote behavior_
16
+
17
+ ## Installation
18
+
19
+ Add Rails Wiki to your Gemfile
20
+
21
+ gem 'rails-wiki'
22
+
23
+ Your application controller needs to provide two methods:
24
+
25
+ - `auth_required` is called on every request
26
+ - `current_user` returns a _user object_
27
+
28
+ The user object must response to `.name` and `.email` with string values.
29
+
30
+ ## Configuration
31
+
32
+ In your `routes.rb`, specify a mount point:
33
+
34
+ mount Wiki::Engine, at: '/wiki'
35
+
36
+ In your `config/environment/*` files, configure the wiki:
37
+
38
+ require 'rails-wiki'
39
+ Wiki.local_directory = 'db/wiki'
40
+
41
+ _TODO: move this configuration to an initializer?_
42
+
43
+ ## Usage
44
+
45
+ Pathnames that begin with underscore (`_`) are reserved.
46
+
47
+ ## Feature Roadmap
48
+
49
+ 1. Markdown link rooting
50
+ 1. Recursive page deletion
51
+ 1. Individual attachment deletion
52
+ 1. Path redirection rules
53
+ 1. Configurable help paths
54
+ 1. Nicer attachment upload
55
+ 1. Nicer page editing
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Rails Wiki'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,34 @@
1
+ // inserts text at cursor, or before and after selection
2
+ // based on http://stackoverflow.com/a/12815163/5610
3
+ jQuery.fn.extend({
4
+ inject: function(insertTextPre, insertTextPost){
5
+ return this.each(function(i) {
6
+ if (document.selection) {
7
+ // IE
8
+ this.focus();
9
+ sel = document.selection.createRange();
10
+ sel.text = insertTextPre + insertTextPost;
11
+ this.focus();
12
+ }
13
+ else if (this.selectionStart || this.selectionStart == '0') {
14
+ // modern browser
15
+ var startPos = this.selectionStart;
16
+ var endPos = this.selectionEnd;
17
+ var scrollTop = this.scrollTop;
18
+ this.value = this.value.substring(0, startPos)+insertTextPre+this.value.substring(startPos,endPos)+insertTextPost+this.value.substring(endPos,this.value.length);
19
+ this.focus();
20
+ this.selectionStart = startPos + insertTextPre.length;
21
+ this.selectionEnd = ((startPos + insertTextPre.length) + this.value.substring(startPos,endPos).length);
22
+ this.scrollTop = scrollTop;
23
+ } else {
24
+ // no selection, only use prefix
25
+ if (document.queryCommandSupported('insertText')) {
26
+ document.execCommand('insertText', false, text);
27
+ } else {
28
+ this.value += insertTextPre;
29
+ this.focus();
30
+ }
31
+ }
32
+ })
33
+ }
34
+ });
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,33 @@
1
+ module Wiki
2
+ # inherit from host app for current_user and auth_required
3
+ class ApplicationController < ::ApplicationController
4
+
5
+ before_filter :auth_required
6
+
7
+ layout 'layouts/wiki'
8
+
9
+ def display
10
+ @home = Rails.configuration.wiki.home_page
11
+
12
+ ext = File.extname(request.path_info).downcase
13
+ if ext.blank? || ext == ".html"
14
+ @page = Rails.configuration.wiki.find_page(params[:path])
15
+ if @page.nil?
16
+ raise Exception.new("Attempt to create orphan page")
17
+ elsif @page.new_page?
18
+ redirect_to controller: :pages, action: :new
19
+ else
20
+ render 'wiki/pages/show'
21
+ end
22
+ else
23
+ @attachment = Rails.configuration.wiki.find_attachment(params[:path], ext)
24
+ if @attachment.blank?
25
+ raise ActionController::RoutingError.new('File Not Found')
26
+ else
27
+ send_file @attachment.filesystem_path, type: @attachment.mime_type, disposition: 'inline'
28
+ end
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,80 @@
1
+ class Wiki::PagesController < Wiki::ApplicationController
2
+
3
+ layout 'layouts/wiki'
4
+
5
+ def index
6
+ select = params[:select]
7
+ query = params[:query]
8
+ if query
9
+ @query = query
10
+ @pages = Rails.configuration.wiki.search(query)
11
+ else
12
+ @pages = Rails.configuration.wiki.all_pages
13
+ end
14
+ end
15
+
16
+ def log
17
+ @changes_by_path = Rails.configuration.wiki.changelog.group_by{|c| c[:path]}
18
+ end
19
+
20
+ def new
21
+ @page = Rails.configuration.wiki.find_page(params[:path])
22
+ render :edit
23
+ end
24
+
25
+ def create
26
+ @page = Rails.configuration.wiki.create_page(params[:path])
27
+ @page.update(page_params)
28
+ if @page.save(current_user)
29
+ redirect_to @page
30
+ else
31
+ render :edit
32
+ end
33
+ end
34
+
35
+ def edit
36
+ Rails.configuration.wiki.pull_repo
37
+ @page = Rails.configuration.wiki.find_page(params[:path])
38
+ end
39
+
40
+ def update
41
+ @page = Rails.configuration.wiki.find_page(params[:path])
42
+ @page.update(page_params)
43
+ if @page.save(current_user)
44
+ redirect_to @page
45
+ else
46
+ render :edit
47
+ end
48
+ end
49
+
50
+ def destroy
51
+ return_path = root_path
52
+ # ext = File.extname(request.path_info).downcase
53
+ # if ext.blank? || ext == "html"
54
+ page = Rails.configuration.wiki.find_page(params[:path])
55
+ parent_path = page.parent_path
56
+ if parent_path.empty?
57
+ return_path = root_path
58
+ else
59
+ return_path = page_path(parent_path)
60
+ end
61
+ page.destroy!(current_user)
62
+ # TODO: recurse pages and attachments
63
+
64
+ # else
65
+ # file = Rails.configuration.wiki.find_file(params[:path] + '.' + params[:format])
66
+ # return_path = page_path(file.parent_path)
67
+ # file.destroy!(current_user)
68
+ # end
69
+
70
+ # TODO: look for first *valid* parent
71
+ redirect_to return_path
72
+ end
73
+
74
+ private
75
+
76
+ def page_params
77
+ params.require(:page).permit(:name, :content, uploaded_files: [])
78
+ end
79
+
80
+ end
@@ -0,0 +1,4 @@
1
+ module Wiki
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,8 @@
1
+ module Wiki
2
+ module WikiHelper
3
+ def wiki_changes(max=10)
4
+ changes = Rails.configuration.wiki.changelog.first(max)
5
+ "<ol>#{render partial: "wiki/change", collection: changes}</ol>".html_safe
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,116 @@
1
+ require 'active_model'
2
+
3
+ module Wiki
4
+ class Attachment
5
+
6
+ include ActiveModel::AttributeMethods
7
+ include ActiveModel::Conversion
8
+ include ActiveModel::Dirty
9
+ extend ActiveModel::Naming
10
+
11
+ define_attribute_methods :name, :content
12
+
13
+ attr_accessor :wiki, :name, :content, :path, :format
14
+ alias :id :path
15
+
16
+ def name=(value)
17
+ name_will_change!
18
+ @name=value unless value.nil?
19
+ end
20
+
21
+ def content=(value)
22
+ content_will_change!
23
+ @content=value unless value.nil?
24
+ end
25
+
26
+ def to_s
27
+ self.path
28
+ end
29
+
30
+ def path
31
+ @path
32
+ end
33
+
34
+ def update(hash)
35
+ self.name = hash[:name]
36
+ self.content = hash[:content]
37
+
38
+ return true
39
+ end
40
+
41
+ def initialize(params={})
42
+ wiki = params[:wiki]
43
+ gollum_file = params[:gollum_file]
44
+ path = params[:path]
45
+
46
+ if wiki
47
+ @wiki = wiki
48
+ end
49
+ if gollum_file
50
+ self.gollum_file = gollum_file
51
+ elsif path
52
+ safepath = path.downcase
53
+ @path = safepath
54
+ new_file = @wiki.find_gollum_file(safepath)
55
+ if new_file
56
+ self.gollum_file = new_file
57
+ end
58
+ end
59
+ end
60
+
61
+ def gollum_file=(file)
62
+ @gollum_file = file
63
+ @name = file.name
64
+ @format = File.extname(file.name).split('.').last.to_sym
65
+ # filename = ::Attachment.basename(fullname, ext)
66
+ @path = file.url_path + file.name
67
+ end
68
+
69
+ def gollum_file
70
+ @gollum_file
71
+ end
72
+
73
+ def filesystem_path
74
+ return File.join(@wiki.base_path, @path)
75
+ end
76
+
77
+ def mime_type
78
+ @gollum_file.mime_type
79
+ end
80
+
81
+ def to_param
82
+ @path
83
+ end
84
+
85
+ def parent_path
86
+ parent_path = File.dirname(@path)
87
+ (parent_path == '.') ? '' : parent_path + '/'
88
+ end
89
+
90
+ def destroy!(user)
91
+ commit_options = {name: user.name, email: user.email, message: "removed #{@path}"}
92
+ Rails.logger.debug("removing #{@path}")
93
+
94
+ committer = Gollum::Committer.new(@wiki.gollum_wiki, commit_options)
95
+ committer.delete(@path)
96
+
97
+ committer.after_commit do |index, _sha|
98
+ dir = File.dirname(@path)
99
+ dir = '' if dir == '.'
100
+
101
+ @wiki.gollum_wiki.clear_cache
102
+ committer.update_working_dir(dir, parent_path, @format)
103
+ end
104
+
105
+ @wiki.pull_repo
106
+ committer.commit
107
+ @wiki.push_repo
108
+ end
109
+
110
+ def persisted?
111
+ # TODO: make this a real dirty flag
112
+ true
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,213 @@
1
+ require 'active_model'
2
+
3
+ module Wiki
4
+ class Page
5
+ # a gollum page facade
6
+
7
+ @@format = :markdown
8
+
9
+ # include ActiveModel::Model
10
+ include ActiveModel::AttributeMethods
11
+ include ActiveModel::Conversion
12
+ include ActiveModel::Dirty
13
+ extend ActiveModel::Naming
14
+
15
+ define_attribute_methods :name, :content
16
+
17
+ attr_accessor :wiki, :name, :content, :path, :uploaded_files
18
+ alias :id :path
19
+
20
+ def name=(value)
21
+ name_will_change!
22
+ @name=value unless value.nil?
23
+ end
24
+
25
+ def content=(value)
26
+ content_will_change!
27
+ @content=value unless value.nil?
28
+ end
29
+
30
+ def to_param
31
+ @path
32
+ end
33
+
34
+ def path
35
+ @path
36
+ end
37
+
38
+ def update(hash)
39
+ self.name = hash[:name]
40
+ self.content = hash[:content]
41
+ @uploaded_files = hash[:uploaded_files]
42
+
43
+ return true
44
+ end
45
+
46
+ def initialize(params={})
47
+ wiki = params[:wiki]
48
+ gollum_page = params[:gollum_page]
49
+ path = params[:path]
50
+
51
+ if wiki
52
+ @wiki = wiki
53
+ end
54
+ if gollum_page
55
+ self.gollum_page = gollum_page
56
+ elsif path
57
+ safepath = path.downcase
58
+ @path = safepath
59
+ new_page = @wiki.find_gollum_page(safepath)
60
+ if new_page
61
+ self.gollum_page = new_page
62
+ else
63
+ @name = safepath.split('/').last
64
+ @blank = true
65
+ end
66
+ end
67
+ end
68
+
69
+ def gollum_page=(new_gp)
70
+ @gollum_page = new_gp
71
+ @name = new_gp.name
72
+ @path = new_gp.url_path
73
+ @content = new_gp.raw_data
74
+ end
75
+
76
+ def gollum_page
77
+ @gollum_page
78
+ end
79
+
80
+ def new_page?
81
+ @blank && true
82
+ end
83
+
84
+ # may be out of sync with @content!
85
+ def html
86
+ @gollum_page.formatted_data unless @blank
87
+ end
88
+
89
+ def metadata
90
+ @gollum_page.metadata
91
+ end
92
+
93
+ # def to_param
94
+ # @gollum_page.url_path unless @blank
95
+ # end
96
+
97
+ def author
98
+ @gollum_page.versions.first.author.name unless @blank
99
+ end
100
+ def authored_date
101
+ @gollum_page.versions.first.authored_date unless @blank
102
+ end
103
+
104
+ def history_url
105
+ # @@format is :markdown, so let's presume
106
+ @wiki.history_url + @path + '.md'
107
+ end
108
+
109
+ def parents
110
+ parents = []
111
+ ancestors = @path.split('/')
112
+ for i in 1..(ancestors.length - 1) do
113
+ parent_name = ancestors.take(i).join('/')
114
+ parents << @wiki.find_page(parent_name)
115
+ end
116
+ return parents
117
+ end
118
+
119
+ def parent_path
120
+ parent_path = File.dirname(@path)
121
+ (parent_path == '.') ? '' : parent_path # + '/'
122
+ end
123
+
124
+ def children
125
+ @wiki.pages_under_path(@path)
126
+ end
127
+
128
+ def attachments
129
+ return @wiki.files_under_path(@path)
130
+ end
131
+
132
+ def save(user)
133
+ if @blank
134
+ commit = {name: user.name, email: user.email, message: "created #{@path}"}
135
+ Rails.logger.debug("creating #{@path}")
136
+
137
+ @wiki.pull_repo
138
+ @wiki.gollum_wiki.write_page(@name, @@format, @content, commit, self.parent_path)
139
+
140
+ @gollum_page = @wiki.find_gollum_page(@path)
141
+ @blank = false
142
+ else
143
+ commit = {name: user.name, email: user.email, message: "updated #{@path}"}
144
+ Rails.logger.debug("saving #{@path}")
145
+
146
+ @wiki.pull_repo
147
+ @wiki.gollum_wiki.update_page(@gollum_page, @name, @@format, @content, commit)
148
+ end
149
+
150
+ if @uploaded_files.present?
151
+ Rails.logger.debug("found #{@uploaded_files.length} new files for #{@path}")
152
+ head = @wiki.gollum_wiki.repo.head
153
+
154
+ # NOTE: may raise Gollum::DuplicatePageError
155
+ commit_options = {
156
+ message: "added #{@uploaded_files.length} attachments to #{@path}",
157
+ name: user.name,
158
+ email: user.email
159
+ }
160
+ committer = Gollum::Committer.new(@wiki.gollum_wiki, commit_options)
161
+
162
+ self.uploaded_files.each do |uploaded|
163
+ # TODO: maybe this should be creating then saving new files
164
+ fullname = uploaded.original_filename
165
+ ext = File.extname(fullname)
166
+ format = ext.split('.').last
167
+ filename = File.basename(fullname, ext)
168
+ contents = uploaded.read
169
+ fsdir = File.join(@wiki.gollum_wiki.path, @path)
170
+ pathname = File.join(@path, fullname)
171
+
172
+ if !FileTest::directory?(fsdir)
173
+ Dir::mkdir(fsdir)
174
+ end
175
+ fspath = File.join(fsdir, fullname)
176
+ File.open(fspath, 'wb') do |file|
177
+ file.write(contents)
178
+ Rails.logger.debug("uploaded #{format} to #{fspath}")
179
+ end
180
+
181
+ committer.index.add(pathname, contents)
182
+ # committer.add_to_index(@path, filename, format, contents)
183
+ # # committer.add_to_index(@path, filename, format, "file")
184
+ committer.after_commit do |committer, sha|
185
+ @wiki.gollum_wiki.clear_cache
186
+ committer.update_working_dir(@path, filename, format)
187
+ end
188
+ end
189
+ committer.commit
190
+ end
191
+
192
+ @wiki.push_repo
193
+ changes_applied
194
+ end
195
+
196
+ def destroy!(user)
197
+ commit = {name: user.name, email: user.email, message: "removed #{@path}"}
198
+ Rails.logger.debug("removing #{@path}")
199
+ @wiki.gollum_wiki.delete_page(@gollum_page, commit)
200
+ @wiki.push_repo
201
+ end
202
+
203
+ def inspect
204
+ "Wiki::Page '#{@path}' (#{@gollum_page})"
205
+ end
206
+
207
+ def persisted?
208
+ # TODO: make this a real dirty flag
209
+ ! self.new_page?
210
+ end
211
+
212
+ end
213
+ end