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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/faalis/dashboard/modules/auth/group.js +7 -1
  3. data/app/assets/javascripts/faalis/dashboard/modules/fields/relation.js +50 -3
  4. data/app/assets/stylesheets/faalis/base.css.scss +16 -1
  5. data/app/assets/stylesheets/faalis/ltr/foundation_and_overrides.scss +4 -0
  6. data/app/assets/stylesheets/faalis/rtl/foundation_and_overrides.css.scss +1 -1
  7. data/app/assets/stylesheets/faalis/variables.css.scss +1 -1
  8. data/app/controllers/faalis/#api_controller.rb# +144 -0
  9. data/app/controllers/faalis/api/v1/#conversations_controller.rb# +120 -0
  10. data/app/controllers/faalis/api/v1/workflows_controller.rb +18 -0
  11. data/app/controllers/faalis/api_controller.rb +3 -3
  12. data/app/controllers/faalis/application_controller.rb +0 -1
  13. data/app/models/faalis/workflow.rb +4 -0
  14. data/app/views/angularjs_templates/auth/groups/new.html +47 -25
  15. data/app/views/angularjs_templates/fields/relation/relation.html +9 -2
  16. data/app/views/devise/sessions/new.html.erb +52 -88
  17. data/app/views/faalis/api/v1/workflows/index.json.jbuilder +5 -0
  18. data/app/views/faalis/home/index.html.erb +14 -11
  19. data/app/views/layouts/faalis/application.html.erb +21 -30
  20. data/app/views/layouts/faalis/simple.html.erb +37 -0
  21. data/app/workflows/faalis/administration_workflow.rb +7 -0
  22. data/config/routes.rb +15 -13
  23. data/db/migrate/20140413180202_create_faalis_workflows.rb +9 -0
  24. data/db/seeds.rb +17 -13
  25. data/lib/faalis.rb +12 -10
  26. data/lib/faalis/engine.rb +9 -8
  27. data/lib/faalis/generators/concerns.rb +15 -13
  28. data/lib/faalis/generators/concerns/bulk.rb +2 -5
  29. data/lib/faalis/generators/concerns/fieldset.rb +48 -0
  30. data/lib/faalis/generators/concerns/resource_fields.rb +43 -45
  31. data/lib/faalis/generators/concerns/where.rb +46 -0
  32. data/lib/faalis/generators/dashboard_scaffold.rb +6 -5
  33. data/lib/faalis/version.rb +1 -1
  34. data/lib/faalis/workflows.rb +7 -0
  35. data/lib/faalis/workflows/base.rb +69 -0
  36. data/lib/faalis/workflows/discovery.rb +42 -0
  37. data/lib/generators/faalis/templates/js/list_view/new.html.erb +7 -5
  38. data/lib/tasks/sync.rake +10 -0
  39. data/spec/factories/faalis_workflows.rb +7 -0
  40. data/spec/models/faalis/workflow_spec.rb +7 -0
  41. metadata +36 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 21454872bc3b4a3814a722386575c01050009a44
4
- data.tar.gz: 9f097e17886a2904a668f50381c56ca7108e1204
3
+ metadata.gz: 57235f4273f0784e21d8a157f8dd9f11b0209f83
4
+ data.tar.gz: a232ef417944fe7e7573d36cb9c554a510146762
5
5
  SHA512:
6
- metadata.gz: 7d15b03eb94e2b704912fa3f0bd55ab1787923b21ee3f56965513bf175ac39e5a3df49d4e28089d2818b78744da953b72ac6f2f1a20636c2a1480315c49e237b
7
- data.tar.gz: acbc8c7e18be3d751f8a440ac25d62094da51d3428854e460f0cced823329834def06d698b26c8e3b35cddb64148773e7d23c2654cac1b282aa871f0bf1a8b22
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
- var permissions = API.all('permissions').getList()
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
- scope.update_collection = function(){
39
- var list_object = API.all(scope.field.to);
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:$lightgray;
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: $dashboard-nav-background;
1258
+ $topbar-bg: $headerbg;
1259
1259
  $topbar-margin-bottom: emCalc(20px);
1260
1260
  $topbar-input-height: emCalc(60px);
1261
1261
  $topbar-transition-speed: 300ms;
@@ -7,7 +7,7 @@ $base_unit: 150px;
7
7
  $wet_asphalt: #34495E;
8
8
  $midnight_blue: #2C3E50;
9
9
 
10
- $headerbg: #111111;
10
+ $headerbg: #4f4f4f;
11
11
  $darkbg: #202224;
12
12
 
13
13
  $clouds: #ecf0f1;
@@ -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