faalis 0.24.4 → 0.25.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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/faalis/dashboard/modules/auth/group.js +7 -1
- data/app/assets/javascripts/faalis/dashboard/modules/fields/relation.js +50 -3
- data/app/assets/stylesheets/faalis/base.css.scss +16 -1
- data/app/assets/stylesheets/faalis/ltr/foundation_and_overrides.scss +4 -0
- data/app/assets/stylesheets/faalis/rtl/foundation_and_overrides.css.scss +1 -1
- data/app/assets/stylesheets/faalis/variables.css.scss +1 -1
- data/app/controllers/faalis/#api_controller.rb# +144 -0
- data/app/controllers/faalis/api/v1/#conversations_controller.rb# +120 -0
- data/app/controllers/faalis/api/v1/workflows_controller.rb +18 -0
- data/app/controllers/faalis/api_controller.rb +3 -3
- data/app/controllers/faalis/application_controller.rb +0 -1
- data/app/models/faalis/workflow.rb +4 -0
- data/app/views/angularjs_templates/auth/groups/new.html +47 -25
- data/app/views/angularjs_templates/fields/relation/relation.html +9 -2
- data/app/views/devise/sessions/new.html.erb +52 -88
- data/app/views/faalis/api/v1/workflows/index.json.jbuilder +5 -0
- data/app/views/faalis/home/index.html.erb +14 -11
- data/app/views/layouts/faalis/application.html.erb +21 -30
- data/app/views/layouts/faalis/simple.html.erb +37 -0
- data/app/workflows/faalis/administration_workflow.rb +7 -0
- data/config/routes.rb +15 -13
- data/db/migrate/20140413180202_create_faalis_workflows.rb +9 -0
- data/db/seeds.rb +17 -13
- data/lib/faalis.rb +12 -10
- data/lib/faalis/engine.rb +9 -8
- data/lib/faalis/generators/concerns.rb +15 -13
- data/lib/faalis/generators/concerns/bulk.rb +2 -5
- data/lib/faalis/generators/concerns/fieldset.rb +48 -0
- data/lib/faalis/generators/concerns/resource_fields.rb +43 -45
- data/lib/faalis/generators/concerns/where.rb +46 -0
- data/lib/faalis/generators/dashboard_scaffold.rb +6 -5
- data/lib/faalis/version.rb +1 -1
- data/lib/faalis/workflows.rb +7 -0
- data/lib/faalis/workflows/base.rb +69 -0
- data/lib/faalis/workflows/discovery.rb +42 -0
- data/lib/generators/faalis/templates/js/list_view/new.html.erb +7 -5
- data/lib/tasks/sync.rake +10 -0
- data/spec/factories/faalis_workflows.rb +7 -0
- data/spec/models/faalis/workflow_spec.rb +7 -0
- metadata +36 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57235f4273f0784e21d8a157f8dd9f11b0209f83
|
4
|
+
data.tar.gz: a232ef417944fe7e7573d36cb9c554a510146762
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5593499cdf0803d93dfe23ea248856ad355d0b05833c31708ec4c81fcbd9914a3d92e80b6c44ada4c32f30bea3eacf3240f10bfb829bae8f6c7a773a6c68802
|
7
|
+
data.tar.gz: a6500a1f72c9fcca90f7936d148c6ea0bb1bdea0c31ab8a7548014297788cac1803438a2d89145d23cf9cc613940c662c374be6266e2f8585b5a35822e789d92
|
@@ -64,6 +64,7 @@ Group.controller("AddGroupController", ["Restangular", "$scope", "$location", "$
|
|
64
64
|
$scope.permissions = [];
|
65
65
|
$scope.editing = false;
|
66
66
|
|
67
|
+
|
67
68
|
$scope.$on("update_perms", function(event) {
|
68
69
|
var sel_perms = [];
|
69
70
|
event.targetScope.selected_perms.forEach(function(perm){
|
@@ -93,8 +94,13 @@ Group.controller("AddGroupController", ["Restangular", "$scope", "$location", "$
|
|
93
94
|
.catch(catch_error);
|
94
95
|
}
|
95
96
|
|
97
|
+
API.all('workflows').getList()
|
98
|
+
.then(function(data){
|
99
|
+
$scope.workflows = data;
|
100
|
+
})
|
101
|
+
.catch(catch_error);
|
96
102
|
|
97
|
-
|
103
|
+
API.all('permissions').getList()
|
98
104
|
.then(function(data){
|
99
105
|
$scope.permissions = data;
|
100
106
|
$scope.$emit("update_perms");
|
@@ -8,6 +8,7 @@ Relation.directive('relationField', ["$filter", "gettext", "Restangular", "catch
|
|
8
8
|
|
9
9
|
function link(scope, element, attrs){
|
10
10
|
var ltr = is_ltr();
|
11
|
+
|
11
12
|
scope.element_id = "id_" + scope.field.name;
|
12
13
|
scope.msg_element_id = "id_" + scope.field.name + "_msg";
|
13
14
|
scope.show_help_btn = false;
|
@@ -34,9 +35,27 @@ Relation.directive('relationField', ["$filter", "gettext", "Restangular", "catch
|
|
34
35
|
return false;
|
35
36
|
}
|
36
37
|
};
|
38
|
+
scope.show_buttons = function() {
|
39
|
+
if ("hide_buttons" in scope.field) {
|
40
|
+
return !scope.field.hide_buttons;
|
41
|
+
}
|
42
|
+
return true;
|
43
|
+
};
|
37
44
|
|
38
|
-
|
39
|
-
|
45
|
+
// Update current field collection list by execute a query on remote end.
|
46
|
+
// if `force` param had non undefined value this method will skip `parent_id`
|
47
|
+
// check
|
48
|
+
scope.update_collection = function(force){
|
49
|
+
if ("parent_id" in scope.field) {
|
50
|
+
if ((scope.field.parent_id === undefined) && (force === undefined)) {
|
51
|
+
return;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
var to = scope.field.to;
|
55
|
+
if (typeof(scope.field.to) === "function") {
|
56
|
+
to = scope.field.to();
|
57
|
+
}
|
58
|
+
var list_object = API.all(to);
|
40
59
|
if ("list_object" in scope.options) {
|
41
60
|
list_object = scope.options.list_object;
|
42
61
|
}
|
@@ -52,7 +71,17 @@ Relation.directive('relationField', ["$filter", "gettext", "Restangular", "catch
|
|
52
71
|
|
53
72
|
scope.update_collection();
|
54
73
|
}
|
55
|
-
|
74
|
+
else {
|
75
|
+
// Add support for `multiple` key in fields with `in` type
|
76
|
+
scope.multiple = function(){
|
77
|
+
if ("multiple" in scope.field) {
|
78
|
+
if (scope.field.multiple !== undefined) {
|
79
|
+
return scope.field.multiple;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
return false;
|
83
|
+
};
|
84
|
+
}
|
56
85
|
// Populate model with new data
|
57
86
|
function update_model_data(){
|
58
87
|
var new_val = $("#" + scope.element_id).val();
|
@@ -75,6 +104,20 @@ Relation.directive('relationField', ["$filter", "gettext", "Restangular", "catch
|
|
75
104
|
}
|
76
105
|
};
|
77
106
|
update_model_data();
|
107
|
+
|
108
|
+
// User can provide a variable to watch on. In case of
|
109
|
+
// any change below function will run. for example:
|
110
|
+
// suppose your select box should update by using value
|
111
|
+
// of other fields. you can add `update-on-change="OtherVar"
|
112
|
+
// to your relation-field.
|
113
|
+
// Remember that in that case you should specify a function
|
114
|
+
// for `to` field of `field-data` which should return a url
|
115
|
+
// of destination resource.
|
116
|
+
scope.$watch('update_on_change', function(newv) {
|
117
|
+
if (newv !== undefined) {
|
118
|
+
scope.update_collection(true);
|
119
|
+
}
|
120
|
+
});
|
78
121
|
}
|
79
122
|
// Actual object of <relation-field> directive
|
80
123
|
return {
|
@@ -108,6 +151,10 @@ Relation.directive('relationField', ["$filter", "gettext", "Restangular", "catch
|
|
108
151
|
// relation field data
|
109
152
|
field: '=fieldData',
|
110
153
|
|
154
|
+
// A variable to watch. in case of change current field
|
155
|
+
// collection will update.
|
156
|
+
update_on_change: '=updateOnChange',
|
157
|
+
|
111
158
|
// Actual Angularjs ng-model
|
112
159
|
model: '='
|
113
160
|
},
|
@@ -49,7 +49,14 @@ footer {
|
|
49
49
|
min-height:60px;
|
50
50
|
position:relative;
|
51
51
|
margin: 0 auto;
|
52
|
-
color
|
52
|
+
color: $lightgray;
|
53
|
+
|
54
|
+
&.plain {
|
55
|
+
background: none;
|
56
|
+
div {
|
57
|
+
padding: 5px;
|
58
|
+
}
|
59
|
+
}
|
53
60
|
|
54
61
|
div{
|
55
62
|
padding:20px 60px;
|
@@ -316,3 +323,11 @@ small.error {
|
|
316
323
|
font-size: 0.6em;
|
317
324
|
color: $lightgray;
|
318
325
|
}
|
326
|
+
|
327
|
+
.single-form {
|
328
|
+
padding-top: 5em;
|
329
|
+
min-height: 35em;
|
330
|
+
fieldset {
|
331
|
+
height: 20em;
|
332
|
+
}
|
333
|
+
}
|
@@ -1,3 +1,5 @@
|
|
1
|
+
@import "faalis/variables";
|
2
|
+
|
1
3
|
// Foundation by ZURB
|
2
4
|
// foundation.zurb.com
|
3
5
|
// Licensed under MIT Open Source
|
@@ -1250,5 +1252,7 @@ $section-title-bg: #f5f5f5;
|
|
1250
1252
|
$section-border-color: #dfdfdf;
|
1251
1253
|
$topbar-margin-bottom: 0;
|
1252
1254
|
$topbar-breakpoint: emCalc(768px); // Change to 9999px for always mobile layout
|
1255
|
+
$topbar-bg: $headerbg;
|
1256
|
+
$topbar-dropdown-toggle-alpha: 0.4;
|
1253
1257
|
|
1254
1258
|
@import 'foundation';
|
@@ -1255,7 +1255,7 @@ $alert-close-position: emCalc(12px);
|
|
1255
1255
|
$section-function-factor: 5%;
|
1256
1256
|
$section-title-bg: #f5f5f5;
|
1257
1257
|
$section-border-color: #dfdfdf;
|
1258
|
-
$topbar-bg: $
|
1258
|
+
$topbar-bg: $headerbg;
|
1259
1259
|
$topbar-margin-bottom: emCalc(20px);
|
1260
1260
|
$topbar-input-height: emCalc(60px);
|
1261
1261
|
$topbar-transition-speed: 300ms;
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
# Faalis - Basic website skel engine
|
3
|
+
# Copyright (C) 2012-2013 Yellowen
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation; either version 2 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License along
|
16
|
+
# with this program; if not, write to the Free Software Foundation, Inc.,
|
17
|
+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
18
|
+
# -----------------------------------------------------------------------------
|
19
|
+
require_dependency "faalis/api_controller"
|
20
|
+
|
21
|
+
|
22
|
+
# This class is the base class of all API controllers in any **Faalis**
|
23
|
+
# host applications. Each host Rails application should have an `APIController`
|
24
|
+
# which inherit from this class.
|
25
|
+
class Faalis::APIController < Faalis::ApplicationController
|
26
|
+
|
27
|
+
@@allowed_fields = []
|
28
|
+
|
29
|
+
# Only support `json` format
|
30
|
+
respond_to :json
|
31
|
+
|
32
|
+
# Authenticate user before any action take place
|
33
|
+
before_filter :authenticate_filter
|
34
|
+
|
35
|
+
# Check for any presence of filtering query, In querystring and load
|
36
|
+
# resource using them
|
37
|
+
before_filter :load_resource_by_query, :only => [:index]
|
38
|
+
|
39
|
+
|
40
|
+
protect_from_forgery
|
41
|
+
|
42
|
+
# Set csrf cookie after any action
|
43
|
+
after_filter :set_csrf_cookie_for_ng
|
44
|
+
|
45
|
+
# Rescue from any access denied exception raised from cancan and
|
46
|
+
# returns a useful error message in json
|
47
|
+
rescue_from CanCan::AccessDenied do |exception|
|
48
|
+
|
49
|
+
render :status => 403, :json => {
|
50
|
+
:error => _("You don't have access to this page"),
|
51
|
+
:orig_msg => exception.message,
|
52
|
+
:action => exception.action,
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def set_csrf_cookie_for_ng
|
57
|
+
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
|
58
|
+
end
|
59
|
+
|
60
|
+
# User authentication for API services take place here. By default
|
61
|
+
# **Faalis** uses the authentication method of **Devise** to authenticate
|
62
|
+
# access to API service.
|
63
|
+
#
|
64
|
+
# If you want to change authentication method ? just override this method
|
65
|
+
# in you **APIController**
|
66
|
+
def authenticate_filter
|
67
|
+
authenticate_user!
|
68
|
+
end
|
69
|
+
|
70
|
+
# Load resource by using parameters specified in querystring.
|
71
|
+
def load_resource_by_query
|
72
|
+
# If any query string parameter provided and allow fields specified
|
73
|
+
if not request.query_parameters.empty? and not allowed_fields.empty?
|
74
|
+
|
75
|
+
logger.info ("Load resource by query parameters")
|
76
|
+
# Iterate over parameters in query string
|
77
|
+
request.query_parameters.each do |key, value|
|
78
|
+
# each key can be like filename[__querytype]=value
|
79
|
+
# which `querytype` is string that specify the query type scope
|
80
|
+
# to use in model. For example these is a query type scope called
|
81
|
+
# `gt` which mean the mentioned field should be greater than the
|
82
|
+
# value
|
83
|
+
field, query_type = key.split("__")
|
84
|
+
|
85
|
+
if allowed_fields.include? field
|
86
|
+
# If field name is in the allowed list
|
87
|
+
# If no query type specified we will use assignment scope.
|
88
|
+
if query_type.nil?
|
89
|
+
query_type = "assignment"
|
90
|
+
end
|
91
|
+
|
92
|
+
# If model have an scope with the "#{query_type}_query" name.
|
93
|
+
# Otherwise skip
|
94
|
+
if model_class.respond_to? "#{query_type}_query"
|
95
|
+
|
96
|
+
# If resource already loaded. If there was a instnace variable
|
97
|
+
# with the plural name of the resource exists then resource
|
98
|
+
# already loaded and we should chain new conditions
|
99
|
+
if instance_variable_defined? "@#{controller_name}"
|
100
|
+
instance_variable_get("@#{controller_name}").send("#{query_type}_query".to_sym, field, value)
|
101
|
+
else
|
102
|
+
# Resource did not loaded we make first query
|
103
|
+
# (without touching database) and set the corresponding
|
104
|
+
# instance variables
|
105
|
+
relation_object = model_class.send("#{query_type}_query".to_sym, field, value)
|
106
|
+
instance_variable_set("@#{controller_name}", relation_object)
|
107
|
+
end
|
108
|
+
|
109
|
+
else
|
110
|
+
logger.info "There is no `#{query_type}_query` in `#{model_class.to_s}` model."
|
111
|
+
end
|
112
|
+
else
|
113
|
+
logger.warn "`#{field}` in not in allowed list for `#{self.class.to_s}`."
|
114
|
+
end
|
115
|
+
end
|
116
|
+
else
|
117
|
+
logger.info("Load resource using `load_resource`")
|
118
|
+
#self.class.load_resource
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# An array of allowed fields for query loading
|
123
|
+
def allowed_fields
|
124
|
+
@@allowed_fields
|
125
|
+
end
|
126
|
+
|
127
|
+
# Using this query you can activate the query loading system
|
128
|
+
# and specify fields which you want to use in query loading
|
129
|
+
def self.allow_query_on(*args)
|
130
|
+
@@allowed_fields = args.to_a.collect { |x| x.to_s }
|
131
|
+
end
|
132
|
+
|
133
|
+
protected
|
134
|
+
|
135
|
+
# Model class related to this controller.
|
136
|
+
def model_class
|
137
|
+
controller_name.singularize.classify.constantize
|
138
|
+
end
|
139
|
+
|
140
|
+
def verified_request?
|
141
|
+
super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require_dependency 'faalis/application_controller'
|
2
|
+
|
3
|
+
module Faalis
|
4
|
+
class API::V1::ConversationsController < ::APIController
|
5
|
+
before_filter :authenticate_user!
|
6
|
+
helper_method :mailbox, :conversation
|
7
|
+
|
8
|
+
def create
|
9
|
+
#binding.pry
|
10
|
+
recipient_emails = message_params(:recipients).split(',')
|
11
|
+
recipients = User.where(email: recipient_emails).all
|
12
|
+
|
13
|
+
@conversation = current_user.
|
14
|
+
send_message(recipients, *message_params(:body, :subject)).conversation
|
15
|
+
|
16
|
+
respond_with(@conversation)
|
17
|
+
end
|
18
|
+
|
19
|
+
def reply
|
20
|
+
@conversation = current_user.reply_to_conversation(conversation, *message_params(:body, :subject))
|
21
|
+
respond_with(@conversation)
|
22
|
+
end
|
23
|
+
|
24
|
+
def trash
|
25
|
+
ids = params[:id].split(",")
|
26
|
+
ids.each do |id|
|
27
|
+
conversation = current_user.mailbox.conversations.find(params[:id])
|
28
|
+
conversation.move_to_trash(current_user)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def untrash
|
33
|
+
ids = params[:id].split(",")
|
34
|
+
ids.each do |id|
|
35
|
+
conversation = current_user.mailbox.conversations.find(params[:id])
|
36
|
+
conversation.untrash(current_user)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def destroy
|
42
|
+
ids = params[:id].split(",")
|
43
|
+
ids.each do |id|
|
44
|
+
conversation = current_user.mailbox.conversations.find(params[:id])
|
45
|
+
current_user.mark_as_deleted conversation
|
46
|
+
#conversation.mark_as_deleted(current_user)
|
47
|
+
end
|
48
|
+
respond_with
|
49
|
+
end
|
50
|
+
|
51
|
+
def index
|
52
|
+
if params[:box] == "inbox"
|
53
|
+
box = "inbox"
|
54
|
+
elsif params[:box] == "sentbox"
|
55
|
+
box = "sentbox"
|
56
|
+
elsif params[:box] == "trash"
|
57
|
+
box = "trash"
|
58
|
+
else
|
59
|
+
respond_to do |f|
|
60
|
+
f.any { head :not_found }
|
61
|
+
end
|
62
|
+
returng
|
63
|
+
end
|
64
|
+
# puts current_user.mailbox.sent.to_json
|
65
|
+
@mailbox ||= current_user.mailbox.send(box.to_sym)
|
66
|
+
respond_with @mailbox
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def show
|
71
|
+
#def conversation
|
72
|
+
@conversations ||= current_user.mailbox.conversations.find(params[:id])
|
73
|
+
@current_user = current_user
|
74
|
+
# @conversation = {}
|
75
|
+
# conversations.each do |conversation|
|
76
|
+
# tmp = {
|
77
|
+
# :receipts => conversation.receipts,
|
78
|
+
# :body => conversation.messages.body,
|
79
|
+
# :is_read => conversation.is_read,
|
80
|
+
# :trashed => conversation.trashed,
|
81
|
+
# :deleted => conversation.deleted,
|
82
|
+
# :recipients => conversation.recipients
|
83
|
+
# }
|
84
|
+
#unless @conversation.include? conversation.id
|
85
|
+
# @conversation[conversation.id] = tmp
|
86
|
+
#end
|
87
|
+
#end
|
88
|
+
|
89
|
+
end
|
90
|
+
private
|
91
|
+
|
92
|
+
def mailbox
|
93
|
+
@mailbox ||= current_user.mailbox
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def conversation
|
98
|
+
@conversation ||= mailbox.conversations.find(params[:id])
|
99
|
+
end
|
100
|
+
|
101
|
+
def conversation_params(*keys)
|
102
|
+
fetch_params(:conversation, *keys)
|
103
|
+
end
|
104
|
+
|
105
|
+
def message_params(*keys)
|
106
|
+
fetch_params(:message, *keys)
|
107
|
+
end
|
108
|
+
|
109
|
+
def fetch_params(key, *subkeys)
|
110
|
+
params[key].instance_eval do
|
111
|
+
case subkeys.size
|
112
|
+
when 0 then self
|
113
|
+
when 1 then
|
114
|
+
self[subkeys.first]
|
115
|
+
else subkeys.map{|k| self[k] }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|