Compare commits
No commits in common. "master" and "32-remove-comment" have entirely different histories.
master
...
32-remove-
25
Gemfile
25
Gemfile
|
@ -1,5 +1,6 @@
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
|
|
||||||
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
||||||
gem 'rails', '4.2.1'
|
gem 'rails', '4.2.1'
|
||||||
# Use sqlite3 as the database for Active Record
|
# Use sqlite3 as the database for Active Record
|
||||||
|
@ -50,25 +51,21 @@ end
|
||||||
|
|
||||||
# Web Server
|
# Web Server
|
||||||
gem 'puma'
|
gem 'puma'
|
||||||
# Environnement .env
|
|
||||||
gem 'dotenv-rails'
|
|
||||||
# Database
|
# Database
|
||||||
gem 'pg'
|
gem 'pg'
|
||||||
|
|
||||||
# Users
|
|
||||||
gem 'devise'
|
|
||||||
# Upload
|
# Upload
|
||||||
gem 'carrierwave'
|
gem 'carrierwave'
|
||||||
# Commentable items
|
# Environnement .env
|
||||||
gem 'acts_as_commentable'
|
gem 'dotenv-rails'
|
||||||
|
# Users
|
||||||
# HTML Templating
|
gem 'devise'
|
||||||
gem 'slim-rails'
|
|
||||||
# Bootstrap
|
|
||||||
gem "twitter-bootstrap-rails"
|
|
||||||
# Pagination
|
# Pagination
|
||||||
gem 'will_paginate'
|
gem 'will_paginate'
|
||||||
|
# Bootstrap
|
||||||
|
gem "twitter-bootstrap-rails"
|
||||||
# Bootstrap for pagination
|
# Bootstrap for pagination
|
||||||
gem 'bootstrap-will_paginate'
|
gem 'bootstrap-will_paginate'
|
||||||
# Autocomplete for ids
|
# HTML Templating
|
||||||
gem 'rails-jquery-autocomplete'
|
gem 'slim-rails'
|
||||||
|
# Commentable items
|
||||||
|
gem 'acts_as_commentable'
|
||||||
|
|
15
Gemfile.lock
15
Gemfile.lock
|
@ -37,7 +37,7 @@ GEM
|
||||||
thread_safe (~> 0.3, >= 0.3.4)
|
thread_safe (~> 0.3, >= 0.3.4)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 1.1)
|
||||||
acts_as_commentable (4.0.2)
|
acts_as_commentable (4.0.2)
|
||||||
arel (6.0.3)
|
arel (6.0.2)
|
||||||
bcrypt (3.1.10)
|
bcrypt (3.1.10)
|
||||||
binding_of_caller (0.7.2)
|
binding_of_caller (0.7.2)
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
|
@ -75,7 +75,7 @@ GEM
|
||||||
railties (~> 4.0)
|
railties (~> 4.0)
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
execjs (2.5.2)
|
execjs (2.5.2)
|
||||||
globalid (0.3.6)
|
globalid (0.3.5)
|
||||||
activesupport (>= 4.1.0)
|
activesupport (>= 4.1.0)
|
||||||
i18n (0.7.0)
|
i18n (0.7.0)
|
||||||
jbuilder (2.3.1)
|
jbuilder (2.3.1)
|
||||||
|
@ -95,7 +95,7 @@ GEM
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mime-types (2.6.1)
|
mime-types (2.6.1)
|
||||||
mini_portile (0.6.2)
|
mini_portile (0.6.2)
|
||||||
minitest (5.8.0)
|
minitest (5.7.0)
|
||||||
multi_json (1.11.2)
|
multi_json (1.11.2)
|
||||||
nokogiri (1.6.6.2)
|
nokogiri (1.6.6.2)
|
||||||
mini_portile (~> 0.6.0)
|
mini_portile (~> 0.6.0)
|
||||||
|
@ -105,7 +105,7 @@ GEM
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.8.1)
|
method_source (~> 0.8.1)
|
||||||
slop (~> 3.4)
|
slop (~> 3.4)
|
||||||
puma (2.12.3)
|
puma (2.12.1)
|
||||||
rack (1.6.4)
|
rack (1.6.4)
|
||||||
rack-test (0.6.3)
|
rack-test (0.6.3)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
|
@ -126,15 +126,13 @@ GEM
|
||||||
activesupport (>= 4.2.0.beta, < 5.0)
|
activesupport (>= 4.2.0.beta, < 5.0)
|
||||||
nokogiri (~> 1.6.0)
|
nokogiri (~> 1.6.0)
|
||||||
rails-deprecated_sanitizer (>= 1.0.1)
|
rails-deprecated_sanitizer (>= 1.0.1)
|
||||||
rails-erd (1.4.2)
|
rails-erd (1.4.1)
|
||||||
activerecord (>= 3.2)
|
activerecord (>= 3.2)
|
||||||
activesupport (>= 3.2)
|
activesupport (>= 3.2)
|
||||||
choice (~> 0.2.0)
|
choice (~> 0.2.0)
|
||||||
ruby-graphviz (~> 1.2)
|
ruby-graphviz (~> 1.2)
|
||||||
rails-html-sanitizer (1.0.2)
|
rails-html-sanitizer (1.0.2)
|
||||||
loofah (~> 2.0)
|
loofah (~> 2.0)
|
||||||
rails-jquery-autocomplete (1.0.3)
|
|
||||||
rails (>= 3.2)
|
|
||||||
railties (4.2.1)
|
railties (4.2.1)
|
||||||
actionpack (= 4.2.1)
|
actionpack (= 4.2.1)
|
||||||
activesupport (= 4.2.1)
|
activesupport (= 4.2.1)
|
||||||
|
@ -216,7 +214,6 @@ DEPENDENCIES
|
||||||
puma
|
puma
|
||||||
rails (= 4.2.1)
|
rails (= 4.2.1)
|
||||||
rails-erd
|
rails-erd
|
||||||
rails-jquery-autocomplete
|
|
||||||
sass-rails (~> 5.0)
|
sass-rails (~> 5.0)
|
||||||
sdoc (~> 0.4.0)
|
sdoc (~> 0.4.0)
|
||||||
slim-rails
|
slim-rails
|
||||||
|
@ -228,4 +225,4 @@ DEPENDENCIES
|
||||||
will_paginate
|
will_paginate
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.11.2
|
1.10.5
|
||||||
|
|
35
README.md
35
README.md
|
@ -16,6 +16,8 @@ I want a simple application, that I __understand__, and that I __need__. By __si
|
||||||
- A pluggable application, with many __REST API__. Because tasks and reports are usefull.
|
- A pluggable application, with many __REST API__. Because tasks and reports are usefull.
|
||||||
- Generic items. I prefere __ONE kind of Bills + Tags__ than __4 ou 5 kinds of Bills__ (for example).
|
- Generic items. I prefere __ONE kind of Bills + Tags__ than __4 ou 5 kinds of Bills__ (for example).
|
||||||
|
|
||||||
|
I would like money, contributions, critics, etc.
|
||||||
|
|
||||||
<img alt="Tickets Desktop view" src="http://i.imgur.com/e004zBZ.png" width="500" />
|
<img alt="Tickets Desktop view" src="http://i.imgur.com/e004zBZ.png" width="500" />
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,19 +31,18 @@ I want a simple application, that I __understand__, and that I __need__. By __si
|
||||||
2. [Contributions](#2-contributions)
|
2. [Contributions](#2-contributions)
|
||||||
1. [Contributors](#21-contributors)
|
1. [Contributors](#21-contributors)
|
||||||
2. [How to contribute](#22-how-to-contribute-)
|
2. [How to contribute](#22-how-to-contribute-)
|
||||||
3. [License](#23-license)
|
|
||||||
3. [Architecture](#3-architecture)
|
|
||||||
1. [Modelisation](#31-modelisation)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 1. Installation
|
# 1. Installation
|
||||||
|
|
||||||
## 1.1. Requirements
|
## 1.1. Requirements
|
||||||
|
|
||||||
- Ruby 2.0 or greater.
|
- Ruby 2.0 or greater.
|
||||||
- Postgresql server 9 or greater running with creditentials.
|
- Postgresql server 9 or greater running with creditentials.
|
||||||
|
|
||||||
## 1.2. Initialization
|
## 1.2. Initialization
|
||||||
|
|
||||||
Start by pasting this script in your shell:
|
Start by pasting this script in your shell:
|
||||||
```bash
|
```bash
|
||||||
cd MorningPeak/
|
cd MorningPeak/
|
||||||
|
@ -55,6 +56,7 @@ rake db:seed # will generate default data. Not on production ;)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 1.3. Configuration
|
## 1.3. Configuration
|
||||||
|
|
||||||
- You can create a file ``.env`` to save your locals cvars without pollute your global env.
|
- You can create a file ``.env`` to save your locals cvars without pollute your global env.
|
||||||
- You can also create ``.env.production`` etc. for environement specifics cvars
|
- You can also create ``.env.production`` etc. for environement specifics cvars
|
||||||
- A ``.env`` file looks like:
|
- A ``.env`` file looks like:
|
||||||
|
@ -68,6 +70,7 @@ LOCALE: fr
|
||||||
- COMPANY
|
- COMPANY
|
||||||
|
|
||||||
## 1.4. First start
|
## 1.4. First start
|
||||||
|
|
||||||
When you done with the configuration of the database (editing ``config/database.yml``),
|
When you done with the configuration of the database (editing ``config/database.yml``),
|
||||||
you can run the server by the following command :
|
you can run the server by the following command :
|
||||||
```
|
```
|
||||||
|
@ -96,6 +99,7 @@ Checkout for [rails minidoc](RailsMinidoc.md) for a resume of rails.
|
||||||
<img alt="Look at this cute face" src="https://pbs.twimg.com/media/CJ_ErJ2W8AAdev3.jpg" width="200" height="150" />
|
<img alt="Look at this cute face" src="https://pbs.twimg.com/media/CJ_ErJ2W8AAdev3.jpg" width="200" height="150" />
|
||||||
|
|
||||||
## 2.2. How to contribute ?
|
## 2.2. How to contribute ?
|
||||||
|
|
||||||
You can contribute to this project by Merge Request on the gitlab repository [here](https://gitlab.com/poulet_a/MorningPeak).
|
You can contribute to this project by Merge Request on the gitlab repository [here](https://gitlab.com/poulet_a/MorningPeak).
|
||||||
The best pratices are to create short commits, and short Merge Requests. Respect the git commit nomage convention as possible with:
|
The best pratices are to create short commits, and short Merge Requests. Respect the git commit nomage convention as possible with:
|
||||||
|
|
||||||
|
@ -106,28 +110,3 @@ The best pratices are to create short commits, and short Merge Requests. Respect
|
||||||
We accept any kind of work : translations, bug fix, additionnal features, optimizations, documentation, etc.
|
We accept any kind of work : translations, bug fix, additionnal features, optimizations, documentation, etc.
|
||||||
|
|
||||||
Don't be afraid !
|
Don't be afraid !
|
||||||
|
|
||||||
## 2.3. License
|
|
||||||
|
|
||||||
see the license in the ``License`` file.
|
|
||||||
|
|
||||||
It is under:
|
|
||||||
|
|
||||||
```text
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
```
|
|
||||||
|
|
||||||
# 3. Architecture
|
|
||||||
|
|
||||||
## 3.1 Modelisation
|
|
||||||
|
|
||||||
### Creation and belongs
|
|
||||||
- User has a Client (which is created when the user is created)
|
|
||||||
- Client has many Contacts and Bills
|
|
||||||
- User/Admin has many Tickets and Comments
|
|
||||||
|
|
||||||
### Permissions
|
|
||||||
- Admin can Comment, Read, Edit, Delete, and Create everything
|
|
||||||
- User can open Ticket, Anwser and Close them.
|
|
||||||
- User can Read every Bills wich is associated to him
|
|
||||||
- User can not read his client informations (like notes, ...)
|
|
||||||
|
|
|
@ -14,6 +14,4 @@
|
||||||
//= require jquery_ujs
|
//= require jquery_ujs
|
||||||
//= require jquery-ui
|
//= require jquery-ui
|
||||||
//= require twitter/bootstrap
|
//= require twitter/bootstrap
|
||||||
//= require jquery-ui/autocomplete
|
|
||||||
//= require autocomplete-rails
|
|
||||||
//= require_tree .
|
//= require_tree .
|
||||||
|
|
|
@ -3,9 +3,6 @@ commentableLoadComments = (base_url) ->
|
||||||
$("#comments").html(e)
|
$("#comments").html(e)
|
||||||
|
|
||||||
$(document).ready ->
|
$(document).ready ->
|
||||||
url = window.location.pathname
|
commentableLoadComments(window.location.href)
|
||||||
commentableLoadComments(url)
|
|
||||||
$(document).on "ajax:success", "#new_comment", (e, data, status, xhr) ->
|
$(document).on "ajax:success", "#new_comment", (e, data, status, xhr) ->
|
||||||
commentableLoadComments(url)
|
commentableLoadComments(window.location.href)
|
||||||
$(document).on "ajax:complete", ".remove-comment", (e, data, status, xhr) ->
|
|
||||||
commentableLoadComments(url)
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
class BillsController < ApplicationController
|
class BillsController < ApplicationController
|
||||||
include CommentableForm
|
include CommentableForm
|
||||||
|
|
||||||
autocomplete :client, :name
|
|
||||||
|
|
||||||
before_action :set_bill, only: [:show, :edit, :update, :destroy]
|
before_action :set_bill, only: [:show, :edit, :update, :destroy]
|
||||||
before_action :authenticate_admin!
|
before_action :authenticate_admin!
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
class ClientTicketsController < ApplicationController
|
class ClientTicketsController < ApplicationController
|
||||||
include CommentableForm
|
|
||||||
|
|
||||||
before_action :set_ticket, only: [:show, :edit, :update, :destroy]
|
before_action :set_ticket, only: [:show, :edit, :update, :destroy]
|
||||||
before_action :set_ticket_custom_route, only: [:close, :open, :respond]
|
before_action :set_ticket_custom_route, only: [:close, :open, :respond]
|
||||||
before_action :looks_ticket, only: [:show, :edit, :update, :close, :open]
|
before_action :looks_ticket, only: [:show, :edit, :update, :close, :open]
|
||||||
|
@ -9,13 +7,13 @@ class ClientTicketsController < ApplicationController
|
||||||
# GET /tickets
|
# GET /tickets
|
||||||
# GET /tickets.json
|
# GET /tickets.json
|
||||||
def index
|
def index
|
||||||
@tickets = current_user.tickets.order('state DESC')
|
@tickets = current_user.tickets.heads.order('state DESC')
|
||||||
end
|
end
|
||||||
|
|
||||||
def close
|
def close
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @ticket.close
|
if @ticket.close
|
||||||
@ticket.update(admin_view_at: Time.now) # add comment ?
|
@ticket.update(admin_view_at: Time.now)
|
||||||
format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully closed.' }
|
format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully closed.' }
|
||||||
format.json { render :show, status: :ok, location: client_tickets_url(@ticket) }
|
format.json { render :show, status: :ok, location: client_tickets_url(@ticket) }
|
||||||
else
|
else
|
||||||
|
@ -28,7 +26,7 @@ class ClientTicketsController < ApplicationController
|
||||||
def open
|
def open
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @ticket.open
|
if @ticket.open
|
||||||
@ticket.update(admin_view_at: nil) # add comment ?
|
@ticket.update(admin_view_at: nil)
|
||||||
format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully reopened.' }
|
format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully reopened.' }
|
||||||
format.json { render :show, status: :ok, location: client_tickets_url(@ticket) }
|
format.json { render :show, status: :ok, location: client_tickets_url(@ticket) }
|
||||||
else
|
else
|
||||||
|
@ -38,10 +36,25 @@ class ClientTicketsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def respond
|
||||||
|
session[:user_ticket_respond_parent_id] = @ticket.id
|
||||||
|
@head = @ticket.head
|
||||||
|
@ticket = Ticket.new(ticket_id: @head.id,
|
||||||
|
creator: current_user,
|
||||||
|
title: @ticket.title)
|
||||||
|
if @ticket.close? or @head.close?
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to client_ticket_url(@head), alert: 'The ticket is closed' }
|
||||||
|
format.json { render json: {ticket: 'The ticket is closed'}, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
|
else
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# GET /tickets/1
|
# GET /tickets/1
|
||||||
# GET /tickets/1.json
|
# GET /tickets/1.json
|
||||||
def show
|
def show
|
||||||
prepare_comment_for @ticket
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /tickets/new
|
# GET /tickets/new
|
||||||
|
@ -57,10 +70,15 @@ class ClientTicketsController < ApplicationController
|
||||||
# POST /tickets.json
|
# POST /tickets.json
|
||||||
def create
|
def create
|
||||||
@ticket = Ticket.new(ticket_params)
|
@ticket = Ticket.new(ticket_params)
|
||||||
|
if session[:user_ticket_respond_parent_id]
|
||||||
|
@head = Ticket.find(session[:user_ticket_respond_parent_id]).head
|
||||||
|
@ticket.ticket_id = @head.id
|
||||||
|
end
|
||||||
@ticket.creator = current_user
|
@ticket.creator = current_user
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @ticket.save
|
if @ticket.save
|
||||||
|
@ticket.close_head if @ticket.close?
|
||||||
format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully created.' }
|
format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully created.' }
|
||||||
format.json { render :show, status: :created, location: client_tickets_url(@ticket) }
|
format.json { render :show, status: :created, location: client_tickets_url(@ticket) }
|
||||||
else
|
else
|
||||||
|
@ -75,6 +93,7 @@ class ClientTicketsController < ApplicationController
|
||||||
def update
|
def update
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @ticket.update(ticket_params)
|
if @ticket.update(ticket_params)
|
||||||
|
@ticket.close_head if @ticket.close?
|
||||||
format.html { redirect_to @ticket, notice: 'Ticket was successfully updated.' }
|
format.html { redirect_to @ticket, notice: 'Ticket was successfully updated.' }
|
||||||
format.json { render :show, status: :ok, location: client_tickets_url(@ticket) }
|
format.json { render :show, status: :ok, location: client_tickets_url(@ticket) }
|
||||||
else
|
else
|
||||||
|
@ -97,11 +116,11 @@ class ClientTicketsController < ApplicationController
|
||||||
private
|
private
|
||||||
# Use callbacks to share common setup or constraints between actions.
|
# Use callbacks to share common setup or constraints between actions.
|
||||||
def set_ticket
|
def set_ticket
|
||||||
@ticket = Ticket.find_by(id: params[:id], creator: current_user)
|
@ticket = Ticket.find(params[:id])
|
||||||
|
@ticket = nil if not @ticket.creator == current_user and not @ticket.head.creator == current_user
|
||||||
@ticket
|
@ticket
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: remove
|
|
||||||
def set_ticket_custom_route
|
def set_ticket_custom_route
|
||||||
params[:id] = params[:client_ticket_id]
|
params[:id] = params[:client_ticket_id]
|
||||||
set_ticket
|
set_ticket
|
||||||
|
@ -113,7 +132,12 @@ class ClientTicketsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def looks_ticket
|
def looks_ticket
|
||||||
@ticket.set_view_by('User')
|
if @ticket.head.head_creator_view_at.nil?
|
||||||
|
@ticket.head.update(head_creator_view_at: Time.now)
|
||||||
|
end
|
||||||
|
Ticket.where(creator: current_user, head_creator_view_at: nil, ticket: @ticket.head).each do |t|
|
||||||
|
t.update(head_creator_view_at: Time.now)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
class ClientsController < ApplicationController
|
class ClientsController < ApplicationController
|
||||||
include CommentableForm
|
include CommentableForm
|
||||||
|
|
||||||
autocomplete :contact, :name
|
|
||||||
|
|
||||||
before_action :authenticate_admin!
|
before_action :authenticate_admin!
|
||||||
before_action :set_client, only: [:show, :edit, :update, :destroy]
|
before_action :set_client, only: [:show, :edit, :update, :destroy]
|
||||||
|
|
||||||
|
|
|
@ -1,53 +1,43 @@
|
||||||
class CommentsController < ApplicationController
|
class CommentsController < ApplicationController
|
||||||
|
before_action :authenticate_admin!
|
||||||
before_action :set_comment, only: [:show, :edit, :update, :destroy]
|
before_action :set_comment, only: [:show, :edit, :update, :destroy]
|
||||||
before_action :set_commentable, only: [:index, :about, :show, :create]
|
before_action :set_client, only: [:index, :about, :new]
|
||||||
before_action :set_commentable_client, only: [:about_client, :show, :create]
|
before_action :set_contact, only: [:index, :about, :new]
|
||||||
|
before_action :set_bill, only: [:index, :about, :new]
|
||||||
|
|
||||||
# GET /comments
|
# GET /comments
|
||||||
# GET /comments.json
|
# GET /comments.json
|
||||||
def index
|
def index
|
||||||
@comments = Comment.where(commentable: @commentable) if @commentable
|
@comments = Comment.all
|
||||||
@comments ||= Comment.where('0=1')
|
@comments = @comments.where(commentable: @commentable) if @commentable
|
||||||
end
|
end
|
||||||
|
|
||||||
def about
|
def about
|
||||||
index()
|
index()
|
||||||
@comment = Comment.new
|
@comment = Comment.new
|
||||||
@comment.commentable = @commentable
|
@comment.commentable = @commentable
|
||||||
render :about, layout: false
|
render :about, layout: false
|
||||||
end
|
end
|
||||||
def about_client
|
|
||||||
index()
|
|
||||||
@comment = Comment.new
|
|
||||||
@comment.commentable = @commentable
|
|
||||||
render :about_client, layout: false
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET /comments/1
|
# GET /comments/1
|
||||||
# GET /comments/1.json
|
# GET /comments/1.json
|
||||||
def show
|
def show
|
||||||
binding.pry
|
|
||||||
render status: :forbidden unless admin_signed_in? or (user_signed_in? and @comment.commentable.is_a? Ticket and @comment.commentable.creator == current_user)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /comments/new
|
# GET /comments/new
|
||||||
def new
|
def new
|
||||||
@comment = Comment.new
|
@comment = Comment.new
|
||||||
@comment.commentable = @commentable
|
@comment.commentable = @commentable
|
||||||
render status: :forbidden unless admin_signed_in? or (user_signed_in? and @comment.commentable.is_a? Ticket and @comment.commentable.creator == current_user)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /comments/1/edit
|
# GET /comments/1/edit
|
||||||
def edit
|
def edit
|
||||||
render status: :forbidden unless admin_signed_in? or (user_signed_in? and @comment.commentable.is_a? Ticket and @comment.commentable.creator == current_user)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# POST /comments
|
# POST /comments
|
||||||
# POST /comments.json
|
# POST /comments.json
|
||||||
def create
|
def create
|
||||||
@comment = Comment.new(comment_params)
|
@comment = Comment.new(comment_params)
|
||||||
@comment.creator = (current_admin || current_user)
|
@comment.creator = current_admin
|
||||||
render status: :forbidden unless admin_signed_in? or (user_signed_in? and @comment.commentable.is_a? Ticket and @comment.commentable.creator == current_user)
|
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @comment.save
|
if @comment.save
|
||||||
|
@ -63,7 +53,6 @@ class CommentsController < ApplicationController
|
||||||
# PATCH/PUT /comments/1
|
# PATCH/PUT /comments/1
|
||||||
# PATCH/PUT /comments/1.json
|
# PATCH/PUT /comments/1.json
|
||||||
def update
|
def update
|
||||||
render status: :forbidden unless admin_signed_in?
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @comment.update(comment_params)
|
if @comment.update(comment_params)
|
||||||
format.html { redirect_to @comment, notice: 'Comment was successfully updated.' }
|
format.html { redirect_to @comment, notice: 'Comment was successfully updated.' }
|
||||||
|
@ -78,7 +67,6 @@ class CommentsController < ApplicationController
|
||||||
# DELETE /comments/1
|
# DELETE /comments/1
|
||||||
# DELETE /comments/1.json
|
# DELETE /comments/1.json
|
||||||
def destroy
|
def destroy
|
||||||
render status: :forbidden unless admin_signed_in?
|
|
||||||
@comment.destroy
|
@comment.destroy
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to comments_url, notice: 'Comment was successfully destroyed.' }
|
format.html { redirect_to comments_url, notice: 'Comment was successfully destroyed.' }
|
||||||
|
@ -99,19 +87,14 @@ class CommentsController < ApplicationController
|
||||||
:role)
|
:role)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_commentable
|
def set_client
|
||||||
return unless admin_signed_in?
|
|
||||||
@commentable ||= Client.find_by_id(params[:client_id])
|
@commentable ||= Client.find_by_id(params[:client_id])
|
||||||
@commentable ||= Contact.find_by_id(params[:contact_id])
|
|
||||||
@commentable ||= Bill.find_by_id(params[:bill_id])
|
|
||||||
@commentable ||= Ticket.find_by_id(params[:ticket_id])
|
|
||||||
@commentable_by = 'Admin'
|
|
||||||
end
|
end
|
||||||
def set_commentable_client
|
def set_contact
|
||||||
return unless user_signed_in?
|
@commentable ||= Contact.find_by_id(params[:contact_id])
|
||||||
if @commentable.nil?
|
end
|
||||||
@commentable ||= Ticket.find_by(id: params[:client_ticket_id], creator: current_user)
|
def set_bill
|
||||||
end
|
@commentable ||= Bill.find_by_id(params[:bill_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
class ContactsController < ApplicationController
|
class ContactsController < ApplicationController
|
||||||
include CommentableForm
|
include CommentableForm
|
||||||
|
|
||||||
autocomplete :client, :name
|
|
||||||
|
|
||||||
before_action :set_contact, only: [:show, :edit, :update, :destroy, :view]
|
before_action :set_contact, only: [:show, :edit, :update, :destroy, :view]
|
||||||
before_action :authenticate_admin!
|
before_action :authenticate_admin!
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ class HomeController < ApplicationController
|
||||||
@next_bills = current_user.bills.next.count
|
@next_bills = current_user.bills.next.count
|
||||||
@old_bills = current_user.bills.old.count
|
@old_bills = current_user.bills.old.count
|
||||||
@bills_count = current_user.bills.count
|
@bills_count = current_user.bills.count
|
||||||
@ticket_closed = current_user.tickets.close.count
|
@ticket_closed = current_user.tickets.heads.close.count
|
||||||
@ticket_opened = current_user.tickets.open.count
|
@ticket_opened = current_user.tickets.heads.open.count
|
||||||
@ticket_waiting = current_user.tickets_unview.count
|
@ticket_waiting = current_user.tickets_unview.count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@ class HomeController < ApplicationController
|
||||||
@next_bills = Bill.next.count
|
@next_bills = Bill.next.count
|
||||||
@old_bills = Bill.old.count
|
@old_bills = Bill.old.count
|
||||||
@bills_count = Bill.count
|
@bills_count = Bill.count
|
||||||
@ticket_closed = Ticket.close.count
|
@ticket_closed = Ticket.heads.close.count
|
||||||
@ticket_opened = Ticket.open.count
|
@ticket_opened = Ticket.heads.open.count
|
||||||
@ticket_waiting = current_admin.tickets_unview.count
|
@ticket_waiting = current_admin.tickets_unview.count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
class TicketsController < ApplicationController
|
class TicketsController < ApplicationController
|
||||||
include CommentableForm
|
|
||||||
|
|
||||||
before_action :set_ticket, only: [:show, :edit, :update, :destroy]
|
before_action :set_ticket, only: [:show, :edit, :update, :destroy]
|
||||||
before_action :set_ticket_custom_route, only: [:close, :open]
|
before_action :set_ticket_custom_route, only: [:close, :open, :respond]
|
||||||
before_action :looks_ticket, only: [:show, :edit, :update, :close, :open]
|
before_action :looks_ticket, only: [:show, :edit, :update, :close, :open]
|
||||||
before_action :authenticate_admin!
|
before_action :authenticate_admin!
|
||||||
|
|
||||||
# GET /tickets
|
# GET /tickets
|
||||||
# GET /tickets.json
|
# GET /tickets.json
|
||||||
def index
|
def index
|
||||||
@tickets = Ticket.order('state DESC')
|
@tickets = Ticket.heads.order('state DESC')
|
||||||
end
|
end
|
||||||
|
|
||||||
def close
|
def close
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @ticket.close
|
if @ticket.close
|
||||||
@ticket.update(admin_view_at: Time.now) # add comment ?
|
@ticket.update(admin_view_at: Time.now)
|
||||||
format.html { redirect_to ticket_url(@ticket), notice: 'Ticket was successfully closed.' }
|
format.html { redirect_to ticket_url(@ticket), notice: 'Ticket was successfully closed.' }
|
||||||
format.json { render :show, status: :ok, location: @ticket }
|
format.json { render :show, status: :ok, location: @ticket }
|
||||||
else
|
else
|
||||||
|
@ -28,7 +26,7 @@ class TicketsController < ApplicationController
|
||||||
def open
|
def open
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @ticket.open
|
if @ticket.open
|
||||||
@ticket.update(creator_view_at: nil) # add comment ?
|
@ticket.update(head_creator_view_at: nil)
|
||||||
format.html { redirect_to ticket_url(@ticket), notice: 'Ticket was successfully reopened.' }
|
format.html { redirect_to ticket_url(@ticket), notice: 'Ticket was successfully reopened.' }
|
||||||
format.json { render :show, status: :ok, location: @ticket }
|
format.json { render :show, status: :ok, location: @ticket }
|
||||||
else
|
else
|
||||||
|
@ -38,10 +36,24 @@ class TicketsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def respond
|
||||||
|
@head = @ticket.head
|
||||||
|
@ticket = Ticket.new(ticket_id: @head.id,
|
||||||
|
creator: current_admin,
|
||||||
|
title: @ticket.title)
|
||||||
|
if @ticket.close? or @head.close?
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to ticket_url(@head), alert: 'the ticket is closed' }
|
||||||
|
format.json { render json: {ticket: 'the ticket is closed'}, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
|
else
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# GET /tickets/1
|
# GET /tickets/1
|
||||||
# GET /tickets/1.json
|
# GET /tickets/1.json
|
||||||
def show
|
def show
|
||||||
prepare_comment_for @ticket
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /tickets/new
|
# GET /tickets/new
|
||||||
|
@ -76,6 +88,7 @@ class TicketsController < ApplicationController
|
||||||
def update
|
def update
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @ticket.update(ticket_params)
|
if @ticket.update(ticket_params)
|
||||||
|
@ticket.close_head if @ticket.close?
|
||||||
format.html { redirect_to @ticket, notice: 'Ticket was successfully updated.' }
|
format.html { redirect_to @ticket, notice: 'Ticket was successfully updated.' }
|
||||||
format.json { render :show, status: :ok, location: @ticket }
|
format.json { render :show, status: :ok, location: @ticket }
|
||||||
else
|
else
|
||||||
|
@ -107,11 +120,16 @@ class TicketsController < ApplicationController
|
||||||
|
|
||||||
# Never trust parameters from the scary internet, only allow the white list through.
|
# Never trust parameters from the scary internet, only allow the white list through.
|
||||||
def ticket_params
|
def ticket_params
|
||||||
params.require(:ticket).permit(:title, :description, :state)
|
params.require(:ticket).permit(:ticket_id, :title, :description, :state)
|
||||||
end
|
end
|
||||||
|
|
||||||
def looks_ticket
|
def looks_ticket
|
||||||
@ticket.set_view_by('Admin')
|
if @ticket.head.admin_view_at.nil?
|
||||||
|
@ticket.head.update(admin_view_at: Time.now)
|
||||||
|
end
|
||||||
|
Ticket.where(creator: current_admin, admin_view_at: nil, ticket: @ticket.head).each do |t|
|
||||||
|
t.update(admin_view_at: Time.now)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Admin < ActiveRecord::Base
|
||||||
has_many :comments, as: :creator
|
has_many :comments, as: :creator
|
||||||
|
|
||||||
def tickets_unview
|
def tickets_unview
|
||||||
Ticket.all.where(admin_view_at: nil)
|
Ticket.all.heads.where(admin_view_at: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
class Client < ActiveRecord::Base
|
class Client < ActiveRecord::Base
|
||||||
acts_as_commentable
|
acts_as_commentable
|
||||||
|
|
||||||
has_many :contacts
|
has_many :contacts
|
||||||
has_many :bills
|
has_many :bills
|
||||||
has_many :tickets, through: :user
|
has_many :tickets, through: :user
|
||||||
|
@ -10,7 +9,7 @@ class Client < ActiveRecord::Base
|
||||||
delegate :name, to: :contact, allow_nil: true, prefix: true
|
delegate :name, to: :contact, allow_nil: true, prefix: true
|
||||||
|
|
||||||
def last_contact
|
def last_contact
|
||||||
contacts.where('view_at IS NOT NULL').pluck(:view_at).max || "never"
|
contacts.pluck(:view_at).max || "never"
|
||||||
end
|
end
|
||||||
|
|
||||||
def bills_retard
|
def bills_retard
|
||||||
|
|
|
@ -3,7 +3,7 @@ class Comment < ActiveRecord::Base
|
||||||
|
|
||||||
belongs_to :commentable, :polymorphic => true
|
belongs_to :commentable, :polymorphic => true
|
||||||
|
|
||||||
default_scope -> { order('created_at DESC') }
|
default_scope -> { order('created_at ASC') }
|
||||||
|
|
||||||
# NOTE: install the acts_as_votable plugin if you
|
# NOTE: install the acts_as_votable plugin if you
|
||||||
# want user to vote on the quality of comments.
|
# want user to vote on the quality of comments.
|
||||||
|
@ -21,11 +21,4 @@ class Comment < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
after_create :update_view_date_for_ticket
|
|
||||||
def update_view_date_for_ticket
|
|
||||||
if commentable.is_a? Ticket
|
|
||||||
commentable.updated_by(creator.class.to_s)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
class Ticket < ActiveRecord::Base
|
class Ticket < ActiveRecord::Base
|
||||||
acts_as_commentable
|
|
||||||
|
|
||||||
# WARNING ! IT REVERSE LAST / FIRST
|
# WARNING ! IT REVERSE LAST / FIRST
|
||||||
default_scope { order('created_at DESC') }
|
default_scope { order('created_at DESC') }
|
||||||
|
|
||||||
|
@ -18,8 +16,12 @@ class Ticket < ActiveRecord::Base
|
||||||
belongs_to :creator, polymorphic: true
|
belongs_to :creator, polymorphic: true
|
||||||
delegate :name, to: :creator, prefix: true
|
delegate :name, to: :creator, prefix: true
|
||||||
|
|
||||||
scope :open, -> { where(state: OPEN) }
|
belongs_to :ticket
|
||||||
scope :close, -> { where(state: CLOSE) }
|
has_many :tickets
|
||||||
|
|
||||||
|
scope :heads, -> { where(ticket_id: nil) }
|
||||||
|
scope :open, -> { heads.where(state: OPEN) }
|
||||||
|
scope :close, -> { heads.where(state: CLOSE) }
|
||||||
|
|
||||||
before_save :check_creator
|
before_save :check_creator
|
||||||
def check_creator
|
def check_creator
|
||||||
|
@ -28,40 +30,39 @@ class Ticket < ActiveRecord::Base
|
||||||
raise ActiveRecord::RecordInvalid.new(self)
|
raise ActiveRecord::RecordInvalid.new(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
after_create :set_view_init
|
after_create :looks_views
|
||||||
def set_view_init
|
def looks_views
|
||||||
set_view_by(creator_type)
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_view_by(viewer_type)
|
|
||||||
if creator_type == 'Admin'
|
if creator_type == 'Admin'
|
||||||
if viewer_type == 'Admin'
|
# Entre admin pas de soucis
|
||||||
update(admin_view_at: Time.now, creator_view_at: Time.now)
|
if head.creator_type == 'Admin'
|
||||||
|
update(admin_view_at: Time.now, head_creator_view_at: Time.now)
|
||||||
|
# Réponse à un client, mise a jour pour notification
|
||||||
|
else
|
||||||
|
update(admin_view_at: Time.now, head_creator_view_at: nil)
|
||||||
|
head.update(admin_view_at: Time.now, head_creator_view_at: nil)
|
||||||
end
|
end
|
||||||
elsif creator_type == 'User'
|
else
|
||||||
if viewer_type == 'User'
|
# Reponse client, mise a jour pour notification
|
||||||
update(creator_view_at: Time.now)
|
if head?
|
||||||
elsif viewer_type == 'Admin'
|
update(admin_view_at: nil, head_creator_view_at: Time.now)
|
||||||
update(admin_view_at: Time.now)
|
else
|
||||||
|
update(admin_view_at: nil, head_creator_view_at: Time.now)
|
||||||
|
head.update(admin_view_at: nil, head_creator_view_at: Time.now)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_unview_by(viewer_type)
|
def last_response
|
||||||
if creator_type == 'Admin'
|
head.tickets.last
|
||||||
return # ... ?
|
|
||||||
elsif creator_type == 'User'
|
|
||||||
if viewer_type == 'User'
|
|
||||||
update(admin_view_at: nil)
|
|
||||||
elsif viewer_type == 'Admin'
|
|
||||||
update(creator_view_at: nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def updated_by(viewer_type)
|
def head
|
||||||
set_view_by(viewer_type)
|
return self if head?
|
||||||
set_unview_by(viewer_type)
|
return ticket.head
|
||||||
|
end
|
||||||
|
|
||||||
|
def head?
|
||||||
|
ticket.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def close
|
def close
|
||||||
|
@ -69,7 +70,15 @@ class Ticket < ActiveRecord::Base
|
||||||
errors[:base] << "Already close"
|
errors[:base] << "Already close"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
update(state: Ticket::CLOSE)
|
head.update(state: Ticket::CLOSE) && update(state: Ticket::CLOSE)
|
||||||
|
end
|
||||||
|
|
||||||
|
def close_head
|
||||||
|
if head.close?
|
||||||
|
errors[:base] << "Already close"
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
head.update(state: Ticket::CLOSE)
|
||||||
end
|
end
|
||||||
|
|
||||||
def open
|
def open
|
||||||
|
@ -77,7 +86,7 @@ class Ticket < ActiveRecord::Base
|
||||||
errors[:base] << "Already open"
|
errors[:base] << "Already open"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
update(state: Ticket::OPEN)
|
head.update(state: Ticket::OPEN) && update(state: Ticket::OPEN)
|
||||||
end
|
end
|
||||||
|
|
||||||
def open?
|
def open?
|
||||||
|
@ -89,7 +98,11 @@ class Ticket < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def short_description
|
def short_description
|
||||||
description.to_s.first(100)
|
if description.size > 100
|
||||||
|
description[0..97] + "..."
|
||||||
|
else
|
||||||
|
description
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,13 +16,11 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
after_create :create_client
|
after_create :create_client
|
||||||
def create_client
|
def create_client
|
||||||
if self.client_id.nil?
|
update(client: Client.create(name: email.gsub(/@.+/, '')))
|
||||||
update_attributes(client: Client.create(name: email.tr('@.-_', ' ')))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def tickets_unview
|
def tickets_unview
|
||||||
tickets.where(creator_view_at: nil)
|
tickets.heads.where(head_creator_view_at: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,9 +9,8 @@
|
||||||
.form-horizontal
|
.form-horizontal
|
||||||
.form-group
|
.form-group
|
||||||
.field
|
.field
|
||||||
= f.autocomplete_field :client, autocomplete_client_name_bills_path, :id_element => '#bill_client_id', class: "form-control", placeholder: "Client Name"
|
|
||||||
= f.label :client_id, class: "sr-only"
|
= f.label :client_id, class: "sr-only"
|
||||||
= f.text_field :client_id, class: "form-control sr-only", placeholder: "#{t('.client_id')}"
|
= f.text_field :client_id, class: "form-control", placeholder: "#{t('.client_id')}"
|
||||||
.form-group
|
.form-group
|
||||||
.field
|
.field
|
||||||
= f.label :title, class: "sr-only"
|
= f.label :title, class: "sr-only"
|
||||||
|
|
|
@ -4,6 +4,7 @@ table.table.table-condensed
|
||||||
thead
|
thead
|
||||||
tr
|
tr
|
||||||
th ID
|
th ID
|
||||||
|
th = t ".creator"
|
||||||
th = t ".title"
|
th = t ".title"
|
||||||
th = t ".description"
|
th = t ".description"
|
||||||
th = t ".state"
|
th = t ".state"
|
||||||
|
@ -12,21 +13,25 @@ table.table.table-condensed
|
||||||
th
|
th
|
||||||
th
|
th
|
||||||
th
|
th
|
||||||
|
th
|
||||||
|
|
||||||
tbody
|
tbody
|
||||||
- @tickets.each do |ticket|
|
- @tickets.each do |ticket|
|
||||||
tr class="#{ticket.creator_view_at.nil? ? 'bg-warning' : ''}"
|
tr class="#{ticket.head_creator_view_at.nil? ? 'bg-warning' : ''}"
|
||||||
td = link_to("##{ticket.id}", client_ticket_path(ticket))
|
td = link_to("##{ticket.id}", client_ticket_path(ticket))
|
||||||
|
td = link_to_creator(ticket)
|
||||||
td = link_to ticket.title, client_ticket_path(ticket)
|
td = link_to ticket.title, client_ticket_path(ticket)
|
||||||
td = ticket.short_description
|
td = ticket.tickets.empty? ? ticket.description : ticket.tickets.first.description
|
||||||
- if ticket.state == Ticket::CLOSE
|
- if ticket.state == Ticket::CLOSE
|
||||||
td.bg-danger = t ".states.close"
|
td.bg-danger = t ".states.close"
|
||||||
- else
|
- else
|
||||||
td.bg-success = t ".states.open"
|
td.bg-success = t ".states.open"
|
||||||
td = ticket.updated_at.to_s(:long)
|
td = ticket.updated_at.to_s(:long)
|
||||||
td = ticket.comments.empty? ? "never" : distance_of_time_in_words_to_now(ticket.comments.first.updated_at)
|
td = ticket.last_response ? distance_of_time_in_words_to_now(ticket.last_response.updated_at) : "never"
|
||||||
td = link_to (t "show"), ticket
|
td = link_to (t "show"), ticket
|
||||||
td = link_to (t "edit"), edit_client_ticket_path(ticket)
|
td = link_to (t "edit"), edit_client_ticket_path(ticket)
|
||||||
|
/ td = link_to 'Destroy', ticket, data: {:confirm => 'Are you sure?'}, :method => :delete
|
||||||
|
td = link_to (t "respond"), client_ticket_respond_path(ticket) if ticket.open?
|
||||||
- if ticket.open?
|
- if ticket.open?
|
||||||
td = link_to (t "close"), client_ticket_close_path(ticket), data: {:confirm => 'Are you sure?'}, :method => :patch
|
td = link_to (t "close"), client_ticket_close_path(ticket), data: {:confirm => 'Are you sure?'}, :method => :patch
|
||||||
- elsif ticket.close?
|
- elsif ticket.close?
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
h1.page-header = "Ticket: #{@ticket.title}"
|
h1.page-header = "Ticket: #{@ticket.head.title}"
|
||||||
|
|
||||||
p
|
p
|
||||||
strong
|
strong
|
||||||
| Id: #
|
| Id: #
|
||||||
= @ticket.id
|
= @ticket.id
|
||||||
p
|
p
|
||||||
strong = t ".title"
|
strong = t ".respond_to"
|
||||||
|:
|
|:
|
||||||
= link_to @ticket.title, client_ticket_path(@ticket)
|
= link_to @ticket.head.title, client_ticket_path(@ticket.head)
|
||||||
|
|
||||||
p
|
p
|
||||||
strong = t ".state"
|
strong = t ".state"
|
||||||
|:
|
|:
|
||||||
- if @ticket.state == Ticket::CLOSE
|
- if @ticket.head.state == Ticket::CLOSE
|
||||||
td.bg-danger = t ".states.close"
|
td.bg-danger = t ".states.close"
|
||||||
- else
|
- else
|
||||||
td.bg-success = t ".states.open"
|
td.bg-success = t ".states.open"
|
||||||
|
@ -31,14 +31,38 @@ p
|
||||||
.container-fluid.ticket-description
|
.container-fluid.ticket-description
|
||||||
= descriptionize @ticket.description
|
= descriptionize @ticket.description
|
||||||
|
|
||||||
== render partial: "/comments/thread", locals: {commentable: @ticket, type: 'user'}
|
- if not @ticket.tickets.empty?
|
||||||
|
table.table.table-condensed
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th = t ".creator"
|
||||||
|
th = t ".title"
|
||||||
|
th = t ".description"
|
||||||
|
th = t ".state"
|
||||||
|
th = t ".last_update"
|
||||||
|
th
|
||||||
|
/ th
|
||||||
|
|
||||||
|
tbody
|
||||||
|
- @ticket.tickets.each do |ticket|
|
||||||
|
tr
|
||||||
|
td = link_to_creator(ticket)
|
||||||
|
td = link_to ticket.title, client_ticket_path(ticket)
|
||||||
|
td = ticket.short_description
|
||||||
|
- if ticket.state == Ticket::CLOSE
|
||||||
|
td.bg-danger = ticket.state
|
||||||
|
- else
|
||||||
|
td.bg-success = ticket.state
|
||||||
|
td = ticket.updated_at.to_s(:long)
|
||||||
|
td = link_to (t "show"), client_ticket_path(ticket)
|
||||||
|
td = link_to (t "edit"), edit_client_ticket_path(ticket)
|
||||||
|
|
||||||
br
|
br
|
||||||
|
|
||||||
- if @ticket.open?
|
- if @ticket.open?
|
||||||
|
= link_to (t 'respond'), client_ticket_respond_path(@ticket), class: 'btn btn-sm btn-default'
|
||||||
= link_to (t 'close'), client_ticket_close_path(@ticket), method: :patch, class: 'btn btn-sm btn-success'
|
= link_to (t 'close'), client_ticket_close_path(@ticket), method: :patch, class: 'btn btn-sm btn-success'
|
||||||
- else
|
- else
|
||||||
= link_to (t 'reopen'), client_ticket_open_path(@ticket), method: :patch, class: 'btn btn-sm btn-danger'
|
= link_to (t 'reopen'), client_ticket_open_path(@ticket), method: :patch, class: 'btn btn-sm btn-danger'
|
||||||
= link_to (t 'edit'), edit_client_ticket_path(@ticket), class: 'btn btn-sm btn-default'
|
= link_to (t 'edit'), edit_client_ticket_path(@ticket), class: 'btn btn-sm btn-default'
|
||||||
= link_to (t 'back'), client_tickets_path, class: 'btn btn-sm btn-default'
|
= link_to (t 'back'), client_tickets_path, class: 'btn btn-sm btn-default'
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
.form-group
|
.form-group
|
||||||
.field
|
.field
|
||||||
= f.label :activity, class: "sr-only"
|
= f.label :activity, class: "sr-only"
|
||||||
= f.text_field :activity, class: "form-control", placeholder: "Activity"
|
= f.text_field :activity, class: "form-control", placeholder: "Acitvity"
|
||||||
.form-group
|
.form-group
|
||||||
.field
|
.field
|
||||||
= f.label :contact_reasons, class: "sr-only"
|
= f.label :contact_reasons, class: "sr-only"
|
||||||
|
@ -30,7 +30,6 @@
|
||||||
= f.text_field :user_id, class: "form-control", placeholder: "User ID"
|
= f.text_field :user_id, class: "form-control", placeholder: "User ID"
|
||||||
.form-group
|
.form-group
|
||||||
.field
|
.field
|
||||||
= f.autocomplete_field :contact, autocomplete_contact_name_clients_path, :id_element => '#client_contact_id', class: "form-control", placeholder: "Main Contact Name"
|
|
||||||
= f.label :contact_id, class: "sr-only"
|
= f.label :contact_id, class: "sr-only"
|
||||||
= f.text_field :contact_id, class: "form-control sr-only", placeholder: "Main Contact ID"
|
= f.text_field :contact_id, class: "form-control", placeholder: "Main Contact ID"
|
||||||
.actions = f.submit class: "btn btn-success"
|
.actions = f.submit class: "btn btn-success"
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
table.table.table-condensed
|
table.table.table-condensed
|
||||||
tr
|
|
||||||
th Creator
|
|
||||||
th Title
|
|
||||||
th Content
|
|
||||||
th
|
|
||||||
- commentable.comments.each do |c|
|
|
||||||
tr
|
tr
|
||||||
td = c.creator_type
|
th Title
|
||||||
td = c.title
|
th Content
|
||||||
td = descriptionize c.comment
|
th
|
||||||
td
|
- commentable.comments.each do |c|
|
||||||
= link_to "/comments/#{c.id}.json", remote: true, data: {:confirm => 'Are you sure?'}, method: :delete, class: "close remove-comment", type: "button", "aria-label" => "Close" do
|
tr
|
||||||
span aria-hidden="true" ×
|
td = c.title
|
||||||
|
td = c.comment
|
||||||
|
td
|
||||||
|
= link_to c, remote: true, data: {:confirm => 'Are you sure?'}, method: :delete, class: "close remove-comment", type: "button", "aria-label": "Close" do
|
||||||
|
span aria-hidden="true" ×
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
table.table.table-condensed
|
|
||||||
tr
|
|
||||||
th Creator
|
|
||||||
th Title
|
|
||||||
th Content
|
|
||||||
- commentable.comments.each do |c|
|
|
||||||
tr
|
|
||||||
td = c.creator_type
|
|
||||||
td = c.title
|
|
||||||
td = descriptionize c.comment
|
|
|
@ -1,4 +0,0 @@
|
||||||
#comments.container-fluid
|
|
||||||
h2.page-header Comments
|
|
||||||
= render partial: "/comments/form"
|
|
||||||
= render partial: "/comments/about#{type == 'user' ? '_client' : '' }", locals: {commentable: commentable}
|
|
|
@ -1 +1,4 @@
|
||||||
== render partial: 'thread', locals: {commentable: @commentable, type: 'admin'}
|
h2 = "Comments"
|
||||||
|
|
||||||
|
== render partial: 'about', locals: {commentable: @commentable}
|
||||||
|
== render partial: '/comments/form'
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
== render partial: 'thread', locals: {commentable: @commentable, type: 'user'}
|
|
|
@ -9,9 +9,8 @@
|
||||||
.form-horizontal
|
.form-horizontal
|
||||||
.form-group
|
.form-group
|
||||||
.field
|
.field
|
||||||
= f.autocomplete_field :client, autocomplete_client_name_contacts_path, :id_element => '#contact_client_id', class: "form-control", placeholder: "Client Name"
|
|
||||||
= f.label :client_id, class: "sr-only"
|
= f.label :client_id, class: "sr-only"
|
||||||
= f.text_field :client_id, class: "form-control sr-only", placeholder: "Client ID"
|
= f.text_field :client_id, class: "form-control", placeholder: "Client ID"
|
||||||
.form-inline
|
.form-inline
|
||||||
.form-group
|
.form-group
|
||||||
.field
|
.field
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
li = message
|
li = message
|
||||||
|
|
||||||
.form-horizontal
|
.form-horizontal
|
||||||
|
.form-group
|
||||||
|
.field
|
||||||
|
= f.label :ticket_id, class: "sr-only"
|
||||||
|
= f.text_field :ticket_id, class: "form-control", placeholder: "Master Ticket id"
|
||||||
.form-group
|
.form-group
|
||||||
.field
|
.field
|
||||||
= f.label :creator_type, class: "sr-only"
|
= f.label :creator_type, class: "sr-only"
|
||||||
|
|
|
@ -14,6 +14,7 @@ table.table.table-condensed.
|
||||||
th
|
th
|
||||||
th
|
th
|
||||||
th
|
th
|
||||||
|
th
|
||||||
|
|
||||||
tbody
|
tbody
|
||||||
- @tickets.each do |ticket|
|
- @tickets.each do |ticket|
|
||||||
|
@ -21,16 +22,17 @@ table.table.table-condensed.
|
||||||
td = link_to("##{ticket.id}", ticket)
|
td = link_to("##{ticket.id}", ticket)
|
||||||
td = link_to_creator(ticket)
|
td = link_to_creator(ticket)
|
||||||
td = link_to ticket.title, ticket
|
td = link_to ticket.title, ticket
|
||||||
td = ticket.short_description
|
td = ticket.tickets.empty? ? ticket.description : ticket.tickets.first.description
|
||||||
- if ticket.state == Ticket::CLOSE
|
- if ticket.state == Ticket::CLOSE
|
||||||
td.bg-danger = ticket.state
|
td.bg-danger = ticket.state
|
||||||
- else
|
- else
|
||||||
td.bg-success = ticket.state
|
td.bg-success = ticket.state
|
||||||
td = ticket.updated_at.to_s(:long)
|
td = ticket.updated_at.to_s(:long)
|
||||||
td = ticket.comments.empty? ? "never" : distance_of_time_in_words_to_now(ticket.comments.first.updated_at)
|
td = ticket.last_response ? distance_of_time_in_words_to_now(ticket.last_response.updated_at) : "never"
|
||||||
td = link_to 'Show', ticket
|
td = link_to 'Show', ticket
|
||||||
td = link_to 'Edit', edit_ticket_path(ticket)
|
td = link_to 'Edit', edit_ticket_path(ticket)
|
||||||
td = link_to 'Destroy', ticket, data: {:confirm => 'Are you sure?'}, :method => :delete
|
td = link_to 'Destroy', ticket, data: {:confirm => 'Are you sure?'}, :method => :delete
|
||||||
|
td = link_to 'Respond', ticket_respond_path(ticket) if ticket.open?
|
||||||
- if ticket.open?
|
- if ticket.open?
|
||||||
td = link_to 'Close', ticket_close_path(ticket), data: {:confirm => 'Are you sure?'}, :method => :patch
|
td = link_to 'Close', ticket_close_path(ticket), data: {:confirm => 'Are you sure?'}, :method => :patch
|
||||||
- elsif ticket.close?
|
- elsif ticket.close?
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
h1.page-header = "Show ticket: #{@ticket.title}"
|
h1.page-header = "Show ticket: #{@ticket.head.title}"
|
||||||
|
|
||||||
p
|
p
|
||||||
strong
|
strong
|
||||||
| Id: #
|
| Id: #
|
||||||
= @ticket.id
|
= @ticket.id
|
||||||
|
p
|
||||||
|
strong Réponse à:
|
||||||
|
= link_to @ticket.head.title, @ticket.head
|
||||||
|
|
||||||
p
|
p
|
||||||
strong State:
|
strong State:
|
||||||
- if @ticket.state == Ticket::CLOSE
|
- if @ticket.head.state == Ticket::CLOSE
|
||||||
td.bg-danger = @ticket.state
|
td.bg-danger = @ticket.head.state
|
||||||
- else
|
- else
|
||||||
td.bg-success = @ticket.state
|
td.bg-success = @ticket.head.state
|
||||||
|
|
||||||
p
|
p
|
||||||
strong Creator:
|
strong Creator:
|
||||||
|
@ -26,13 +29,38 @@ p
|
||||||
strong State:
|
strong State:
|
||||||
= @ticket.state
|
= @ticket.state
|
||||||
|
|
||||||
|
table.table.table-condensed.
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th Creator
|
||||||
|
th Title
|
||||||
|
th Description
|
||||||
|
th Last update
|
||||||
|
th
|
||||||
|
th
|
||||||
|
th
|
||||||
|
|
||||||
|
tbody
|
||||||
|
- @ticket.tickets.each do |ticket|
|
||||||
|
tr
|
||||||
|
td = link_to_creator(ticket)
|
||||||
|
td = link_to ticket.title, ticket
|
||||||
|
td = ticket.description
|
||||||
|
- if ticket.state == Ticket::CLOSE
|
||||||
|
td.bg-danger = ticket.state
|
||||||
|
- else
|
||||||
|
td.bg-success = ticket.state
|
||||||
|
td = ticket.updated_at.to_s(:long)
|
||||||
|
td = link_to 'Show', ticket
|
||||||
|
td = link_to 'Edit', edit_ticket_path(ticket)
|
||||||
|
td = link_to 'Destroy', ticket, data: {:confirm => 'Are you sure?'}, :method => :delete
|
||||||
|
|
||||||
br
|
br
|
||||||
|
|
||||||
- if @ticket.open?
|
- if @ticket.open?
|
||||||
|
= link_to 'Respond', ticket_respond_path(@ticket), class: 'btn btn-sm btn-default'
|
||||||
= link_to 'Close', ticket_close_path(@ticket), method: :patch, class: 'btn btn-sm btn-success'
|
= link_to 'Close', ticket_close_path(@ticket), method: :patch, class: 'btn btn-sm btn-success'
|
||||||
- else
|
- else
|
||||||
= link_to 'Reopen', ticket_open_path(@ticket), method: :patch, class: 'btn btn-sm btn-danger'
|
= link_to 'Reopen', ticket_open_path(@ticket), method: :patch, class: 'btn btn-sm btn-danger'
|
||||||
= link_to 'Edit', edit_ticket_path(@ticket), class: 'btn btn-sm btn-default'
|
= link_to 'Edit', edit_ticket_path(@ticket), class: 'btn btn-sm btn-default'
|
||||||
= link_to 'Back', tickets_path, class: 'btn btn-sm btn-default'
|
= link_to 'Back', tickets_path, class: 'btn btn-sm btn-default'
|
||||||
|
|
||||||
== render partial: "/comments/thread", locals: {commentable: @ticket, type: 'admin'}
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
# Be sure to restart your server when you modify this file.
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
Rails.application.config.session_store :cookie_store, key: '_MorningPeak_session'
|
Rails.application.config.session_store :cookie_store, key: '_WebImmo_session'
|
||||||
|
|
|
@ -2,23 +2,15 @@ Rails.application.routes.draw do
|
||||||
root to: "home#index"
|
root to: "home#index"
|
||||||
match "/help", to: "home#help", via: [:get], as: 'help'
|
match "/help", to: "home#help", via: [:get], as: 'help'
|
||||||
|
|
||||||
resources :comments
|
|
||||||
|
|
||||||
# ----- ADMINISTRATION -----
|
# ----- ADMINISTRATION -----
|
||||||
|
|
||||||
resources :tickets do
|
resources :tickets do
|
||||||
patch :close
|
patch :close
|
||||||
patch :open
|
patch :open
|
||||||
resources :comments do
|
get :respond
|
||||||
collection do
|
|
||||||
get 'about'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
resources :comments
|
||||||
resources :contacts do
|
resources :contacts do
|
||||||
get :autocomplete_client_name, :on => :collection
|
|
||||||
resources :comments do
|
resources :comments do
|
||||||
collection do
|
collection do
|
||||||
get 'about'
|
get 'about'
|
||||||
|
@ -28,7 +20,6 @@ Rails.application.routes.draw do
|
||||||
match '/contacts/:id/view', to: 'contacts#view', via: [:patch, :get], as: 'view_contact'
|
match '/contacts/:id/view', to: 'contacts#view', via: [:patch, :get], as: 'view_contact'
|
||||||
|
|
||||||
resources :bills do
|
resources :bills do
|
||||||
get :autocomplete_client_name, :on => :collection
|
|
||||||
resources :comments do
|
resources :comments do
|
||||||
collection do
|
collection do
|
||||||
get 'about'
|
get 'about'
|
||||||
|
@ -37,7 +28,6 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :clients do
|
resources :clients do
|
||||||
get :autocomplete_contact_name, :on => :collection
|
|
||||||
resources :comments do
|
resources :comments do
|
||||||
collection do
|
collection do
|
||||||
get 'about'
|
get 'about'
|
||||||
|
@ -49,7 +39,6 @@ Rails.application.routes.draw do
|
||||||
match "/users/dashboard", to: 'home#user_dashboard', via: [:get], as: 'users_dashboard'
|
match "/users/dashboard", to: 'home#user_dashboard', via: [:get], as: 'users_dashboard'
|
||||||
match "/users", to: redirect('/users/dashboard'), via: [:get]
|
match "/users", to: redirect('/users/dashboard'), via: [:get]
|
||||||
devise_for :users
|
devise_for :users
|
||||||
|
|
||||||
match "/admins/dashboard", to: 'home#admin_dashboard', via: [:get], as: 'admins_dashboard'
|
match "/admins/dashboard", to: 'home#admin_dashboard', via: [:get], as: 'admins_dashboard'
|
||||||
match "/admins", to: redirect('/admins/dashboard'), via: [:get]
|
match "/admins", to: redirect('/admins/dashboard'), via: [:get]
|
||||||
match "/admins/export", to: "home#export", via: [:get], as: 'admins_export'
|
match "/admins/export", to: "home#export", via: [:get], as: 'admins_export'
|
||||||
|
@ -59,12 +48,62 @@ Rails.application.routes.draw do
|
||||||
resources :client_tickets, path: '/client/tickets' do
|
resources :client_tickets, path: '/client/tickets' do
|
||||||
patch :close
|
patch :close
|
||||||
patch :open
|
patch :open
|
||||||
resources :comments do
|
get :respond
|
||||||
collection do
|
|
||||||
get 'about', to: 'comments#about_client'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
resources :client_bills, path: '/client/bills'
|
resources :client_bills, path: '/client/bills'
|
||||||
|
|
||||||
|
# The priority is based upon order of creation: first created -> highest priority.
|
||||||
|
# See how all your routes lay out with "rake routes".
|
||||||
|
|
||||||
|
# You can have the root of your site routed with "root"
|
||||||
|
# root 'welcome#index'
|
||||||
|
|
||||||
|
# Example of regular route:
|
||||||
|
# get 'products/:id' => 'catalog#view'
|
||||||
|
|
||||||
|
# Example of named route that can be invoked with purchase_url(id: product.id)
|
||||||
|
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
|
||||||
|
|
||||||
|
# Example resource route (maps HTTP verbs to controller actions automatically):
|
||||||
|
# resources :products
|
||||||
|
|
||||||
|
# Example resource route with options:
|
||||||
|
# resources :products do
|
||||||
|
# member do
|
||||||
|
# get 'short'
|
||||||
|
# post 'toggle'
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# collection do
|
||||||
|
# get 'sold'
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Example resource route with sub-resources:
|
||||||
|
# resources :products do
|
||||||
|
# resources :comments, :sales
|
||||||
|
# resource :seller
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Example resource route with more complex sub-resources:
|
||||||
|
# resources :products do
|
||||||
|
# resources :comments
|
||||||
|
# resources :sales do
|
||||||
|
# get 'recent', on: :collection
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Example resource route with concerns:
|
||||||
|
# concern :toggleable do
|
||||||
|
# post 'toggle'
|
||||||
|
# end
|
||||||
|
# resources :posts, concerns: :toggleable
|
||||||
|
# resources :photos, concerns: :toggleable
|
||||||
|
|
||||||
|
# Example resource route within a namespace:
|
||||||
|
# namespace :admin do
|
||||||
|
# # Directs /admin/products/* to Admin::ProductsController
|
||||||
|
# # (app/controllers/admin/products_controller.rb)
|
||||||
|
# resources :products
|
||||||
|
# end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
class UpdateTickets < ActiveRecord::Migration
|
|
||||||
def change
|
|
||||||
|
|
||||||
rename_column :tickets, :head_creator_view_at, :creator_view_at
|
|
||||||
remove_column :tickets, :ticket_id
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
15
db/schema.rb
15
db/schema.rb
|
@ -11,7 +11,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20160131000119) do
|
ActiveRecord::Schema.define(version: 20150725193246) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -41,7 +41,7 @@ ActiveRecord::Schema.define(version: 20160131000119) do
|
||||||
t.text "description"
|
t.text "description"
|
||||||
t.integer "amount"
|
t.integer "amount"
|
||||||
t.boolean "paid", default: false, null: false
|
t.boolean "paid", default: false, null: false
|
||||||
t.date "emission_date", default: '2016-01-30', null: false
|
t.date "emission_date", default: '2015-07-24', null: false
|
||||||
t.date "due_date", null: false
|
t.date "due_date", null: false
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
|
@ -96,16 +96,18 @@ ActiveRecord::Schema.define(version: 20160131000119) do
|
||||||
create_table "tickets", force: :cascade do |t|
|
create_table "tickets", force: :cascade do |t|
|
||||||
t.integer "creator_id"
|
t.integer "creator_id"
|
||||||
t.string "creator_type"
|
t.string "creator_type"
|
||||||
|
t.integer "ticket_id"
|
||||||
t.string "title"
|
t.string "title"
|
||||||
t.text "description"
|
t.text "description"
|
||||||
t.string "state", default: "open", null: false
|
t.string "state", default: "open", null: false
|
||||||
t.time "admin_view_at"
|
t.time "admin_view_at"
|
||||||
t.time "creator_view_at"
|
t.time "head_creator_view_at"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "tickets", ["creator_type", "creator_id"], name: "index_tickets_on_creator_type_and_creator_id", using: :btree
|
add_index "tickets", ["creator_type", "creator_id"], name: "index_tickets_on_creator_type_and_creator_id", using: :btree
|
||||||
|
add_index "tickets", ["ticket_id"], name: "index_tickets_on_ticket_id", using: :btree
|
||||||
|
|
||||||
create_table "users", force: :cascade do |t|
|
create_table "users", force: :cascade do |t|
|
||||||
t.string "email", default: "", null: false
|
t.string "email", default: "", null: false
|
||||||
|
@ -127,4 +129,5 @@ ActiveRecord::Schema.define(version: 20160131000119) do
|
||||||
|
|
||||||
add_foreign_key "bills", "clients"
|
add_foreign_key "bills", "clients"
|
||||||
add_foreign_key "contacts", "clients"
|
add_foreign_key "contacts", "clients"
|
||||||
|
add_foreign_key "tickets", "tickets"
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user