faalis 0.24.4 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
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