Skip to content

Commit

Permalink
Add documents foodcoops#353
Browse files Browse the repository at this point in the history
  • Loading branch information
paroga committed Feb 25, 2016
1 parent bdeb0b1 commit 3f7556c
Show file tree
Hide file tree
Showing 21 changed files with 327 additions and 1 deletion.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ gem 'ruby-filemagic'
gem 'acts_as_versioned', github: 'technoweenie/acts_as_versioned'
gem 'foodsoft_wiki', path: 'plugins/wiki'
gem 'foodsoft_messages', path: 'plugins/messages'
gem 'foodsoft_documents', path: 'plugins/documents'

# plugins not enabled by default
#gem 'foodsoft_current_orders', path: 'plugins/current_orders'
Expand Down
8 changes: 8 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ GIT
acts_as_versioned (0.6.0)
activerecord (>= 3.0.9)

PATH
remote: plugins/documents
specs:
foodsoft_documents (0.0.1)
deface (~> 1.0.0)
rails

PATH
remote: plugins/messages
specs:
Expand Down Expand Up @@ -494,6 +501,7 @@ DEPENDENCIES
exception_notification
factory_girl_rails
faker
foodsoft_documents!
foodsoft_messages!
foodsoft_wiki!
gaffe
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# This migration comes from foodsoft_documents_engine (originally 20160220000000)
class CreateDocuments < ActiveRecord::Migration
def self.up
create_table :documents do |t|
t.string :name
t.string :mime
t.binary :data, limit: 16.megabyte
t.integer :created_by_user_id
t.timestamps
end
end

def self.down
drop_table :documents
end
end
11 changes: 10 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20160219123220) do
ActiveRecord::Schema.define(version: 20160220000000) do

create_table "article_categories", force: :cascade do |t|
t.string "name", limit: 255, default: "", null: false
Expand Down Expand Up @@ -76,6 +76,15 @@

add_index "deliveries", ["supplier_id"], name: "index_deliveries_on_supplier_id", using: :btree

create_table "documents", force: :cascade do |t|
t.string "name"
t.string "mime"
t.binary "data"
t.integer "created_by_user_id"
t.datetime "created_at"
t.datetime "updated_at"
end

create_table "financial_transaction_classes", force: :cascade do |t|
t.string "name", null: false
end
Expand Down
18 changes: 18 additions & 0 deletions plugins/documents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FoodsoftDocuments
=================

This plugin adds documents to foodsoft. A new 'Documents' menu entry is added below the 'Foodcoops' menu in the navigation bar.

This plugin is enabled by default in foodsoft, so you don't need to do anything
to install it. If you still want to, for example when it has been disabled,
add the following to foodsoft's Gemfile:

```Gemfile
gem 'foodsoft_documents', path: 'lib/foodsoft_documents'
```

This plugin introduces the foodcoop config option `use_documents`, which can be
set to `true` to enable documents. May be useful in multicoop deployments.

This plugin is part of the foodsoft package and uses the GPL-3 license (see
foodsoft's LICENSE for the full license text).
40 changes: 40 additions & 0 deletions plugins/documents/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env rake
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
begin
require 'rdoc/task'
rescue LoadError
require 'rdoc/rdoc'
require 'rake/rdoctask'
RDoc::Task = Rake::RDocTask
end

RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'FoodsoftDocuments'
rdoc.options << '--line-numbers'
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('lib/**/*.rb')
end

APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
load 'rails/tasks/engine.rake'



Bundler::GemHelper.install_tasks

require 'rake/testtask'

Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = false
end


task :default => :test
61 changes: 61 additions & 0 deletions plugins/documents/app/controllers/documents_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
require 'filemagic'

class DocumentsController < ApplicationController
before_filter -> { require_plugin_enabled FoodsoftDocuments }

def index
if params["sort"]
sort = case params["sort"]
when "name" then "name"
when "created_at" then "created_at"
when "name_reverse" then "name DESC"
when "created_at_reverse" then "created_at DESC"
end
else
sort = "name"
end

@documents = Document.page(params[:page]).per(@per_page).order(sort)
end

def new
@document = Document.new
end

def create
@document = Document.new
@document.data = params[:document][:data].read
@document.mime = FileMagic.new(FileMagic::MAGIC_MIME).buffer(@document.data)
if params[:document][:name] == ''
@document.name = params[:document][:data].original_filename
else
@document.name = params[:document][:name]
end
@document.created_by = current_user
@document.save!
redirect_to documents_path, notice: I18n.t('documents.create.notice')
rescue => error
redirect_to documents_path, alert: t('documents.create.error', error: error.message)
end

def destroy
@document = Document.find(params[:id])
if @document.created_by == current_user or current_user.role_admin?
@document.destroy
redirect_to documents_path, notice: t('documents.destroy.notice')
else
redirect_to documents_path, alert: t('documents.destroy.no_right')
end
rescue => error
redirect_to documents_path, alert: t('documents.destroy.error', error: error.message)
end

def show
@document = Document.find(params[:id])
filename = @document.name
unless filename.include? '.'
filename += '.' + MIME::Types[@document.mime].first.preferred_extension
end
send_data(@document.data, :filename => filename, :type => @document.mime)
end
end
5 changes: 5 additions & 0 deletions plugins/documents/app/models/document.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Document < ActiveRecord::Base
belongs_to :created_by, :class_name => 'User', :foreign_key => 'created_by_user_id'

validates_presence_of :data
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/ insert_before ':root:first-child'
= config_input form, :use_documents, as: :boolean
20 changes: 20 additions & 0 deletions plugins/documents/app/views/documents/_documents.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
- if Document.count > 20
= items_per_page
= pagination_links_remote @documents
%table.table.table-striped
%thead
%tr
%th= sort_link_helper heading_helper(Document, :name), "name", :per_page => @per_page
%th= sort_link_helper heading_helper(Document, :created_at), "created_at", :per_page => @per_page
%th= heading_helper(Document, :created_by)
%th
%tbody
- for document in @documents
%tr
%td= link_to document.name, document
%td= format_time(document.created_at)
%td= h show_user(document.created_by)
%td
- if document.created_by == current_user or current_user.role_admin?
= link_to t('ui.delete'), document, :method => :delete, :data => {:confirm => t('admin.confirm', name: document.name)},
class: 'btn btn-mini btn-danger'
7 changes: 7 additions & 0 deletions plugins/documents/app/views/documents/index.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
- title t('.title')

- content_for :actionbar do
= link_to t('.new'), new_document_path, class: 'btn btn-primary'

#documentsTable
= render :partial => "documents"
1 change: 1 addition & 0 deletions plugins/documents/app/views/documents/index.js.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$('#documentsTable').html('#{escape_javascript(render("documents"))}');
8 changes: 8 additions & 0 deletions plugins/documents/app/views/documents/new.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- title t('.title')

= simple_form_for(@document) do |f|
= f.input :name, as: :string
= f.input :data, as: :file
.form-actions
= f.submit class: 'btn'
= link_to t('ui.or_cancel'), :back
29 changes: 29 additions & 0 deletions plugins/documents/config/locales/de.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
de:
activerecord:
attributes:
document:
created_at: Erstellt am
created_by_user_id: Erstellt von
data: Daten
mime: MIME-Typ
name: Name
config:
hints:
use_documents: Einfache Dokumentenverwaltung aktivieren
keys:
use_documents: Dokumente verwenden
navigation:
documents: Dokumente
documents:
create:
error: 'Dokument konnte nicht erstellt werden: %{error}'
notice: Dokument wurde erstellt
destroy:
error: 'Dokument konnt nicht gelöscht werden: %{error}'
no_right: Du hast nicht genügend Rechte um die Datei zu löschen
notice: Dokument wurde gelöscht
index:
new: Neues Dokument anlegen
title: Dokumente
new:
title: Neues Dokument
29 changes: 29 additions & 0 deletions plugins/documents/config/locales/en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
en:
activerecord:
attributes:
document:
created_at: Created at
created_by_user_id: Created by
data: Data
mime: MIME type
name: Name
config:
hints:
use_documents: Add a basic document sharing page to the foodcoop menu.
keys:
use_documents: Enable documents
navigation:
documents: Documents
documents:
create:
error: 'Document could not be created: %{error}'
notice: Document was created
destroy:
error: 'Document could not be deleted: %{error}'
no_right: You do not have enough rights to delete the document
notice: Document was deleted
index:
new: Upload new document
title: Documents
new:
title: New Document
9 changes: 9 additions & 0 deletions plugins/documents/config/routes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Rails.application.routes.draw do

scope '/:foodcoop' do

resources :documents

end

end
15 changes: 15 additions & 0 deletions plugins/documents/db/migrate/20160220000000_create_documents.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class CreateDocuments < ActiveRecord::Migration
def self.up
create_table :documents do |t|
t.string :name
t.string :mime
t.binary :data, limit: 16.megabyte
t.integer :created_by_user_id
t.timestamps
end
end

def self.down
drop_table :documents
end
end
21 changes: 21 additions & 0 deletions plugins/documents/foodsoft_documents.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
$:.push File.expand_path("../lib", __FILE__)

# Maintain your gem's version:
require "foodsoft_documents/version"

# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
s.name = "foodsoft_documents"
s.version = FoodsoftDocuments::VERSION
s.authors = ["paroga"]
s.email = ["paroga@paroga.com"]
s.homepage = "https://github.com/foodcoops/foodsoft"
s.summary = "Documents plugin for foodsoft."
s.description = "Adds simple document management to foodsoft."

s.files = Dir["{app,config,db,lib}/**/*"] + ["Rakefile", "README.md"]
s.test_files = Dir["test/**/*"]

s.add_dependency "rails"
s.add_dependency "deface", "~> 1.0.0"
end
9 changes: 9 additions & 0 deletions plugins/documents/lib/foodsoft_documents.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require 'foodsoft_documents/engine'

module FoodsoftDocuments
# Return whether the documents are used or not.
# Enabled by default in {FoodsoftConfig} since it used to be part of the foodsoft core.
def self.enabled?
FoodsoftConfig[:use_documents]
end
end
15 changes: 15 additions & 0 deletions plugins/documents/lib/foodsoft_documents/engine.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module FoodsoftDocuments
class Engine < ::Rails::Engine
def navigation(primary, context)
return unless FoodsoftDocuments.enabled?
return if primary[:foodcoop].nil?
sub_nav = primary[:foodcoop].sub_navigation
sub_nav.items <<
SimpleNavigation::Item.new(primary, :documents, I18n.t('navigation.documents'), context.documents_path)
# move to right before tasks item
if i = sub_nav.items.index(sub_nav[:tasks])
sub_nav.items.insert(i, sub_nav.items.delete_at(-1))
end
end
end
end
3 changes: 3 additions & 0 deletions plugins/documents/lib/foodsoft_documents/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module FoodsoftDocuments
VERSION = "0.0.1"
end

4 comments on commit 3f7556c

@wvengen
Copy link

@wvengen wvengen commented on 3f7556c Mar 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to have this as a plugin? Sorry to be such a nuisance, but I'm not convenced that the security concerns in this comment are addressed. Whilelisting extensions/filetypes + sanitizing filenames is missing.

@wvengen
Copy link

@wvengen wvengen commented on 3f7556c Mar 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also move this to a new PR.

@paroga
Copy link
Owner Author

@paroga paroga commented on 3f7556c Mar 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't see how this security points are relevant: we write the stuff 1:1 into the db (so no problems with wrong paths, executable files or anything like that) and we send it 1:1 back to the user.
If a bad user uploads bad things for an other user we can not avoid this (e.g. DOC might a valid filetype, but can contain malicious data), but I do not see how it has any impact on foodsoft.

the change it is in the old PR already too ;-)

@wvengen
Copy link

@wvengen wvengen commented on 3f7556c Mar 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, it's not really a problem on the server, but for users. I guess it's ok to skip the whitelist.
I'd still like to sanitize the filename, e.g. https://matt.berther.io/2007/10/19/uploading-files-to-a-database-using-rails/ .

Please sign in to comment.