Page MenuHomeGRNET

No OneTemporary

File Metadata

Created
Fri, Aug 8, 8:44 PM
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css
index 320c6f7..b0e1d28 100644
--- a/app/assets/stylesheets/application.css
+++ b/app/assets/stylesheets/application.css
@@ -1,87 +1,92 @@
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any styles
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
* file per style scope.
*
*= require bootstrap.min
*= require jstree-default
*= require bootstrap-chosen
*= require dataTables.bootstrap.min
*= require jquery.timepicker.min
*= require_tree .
*= require_self
*/
/* Make sure navbar does not overlay body */
body {
padding-top: 70px;
}
.right {
text-align: right;
margin-right: 0px;
float: right;
}
.graybox {
max-width: 500px;
margin-right: 0;
margin-left: 0;
background-color: #F7F7F9;
margin-bottom: 30px;
}
.graybox form {
padding-top: 30px;
}
#_days_back {
margin: auto 10px;
}
tr.fatal > td {
background-color: #EA7272;
}
tr.fatal > td {
background-color: #EA7272;
}
li.logo {
}
li.logo > a {
padding-left: 60px;
background: url('/images/logo.png') no-repeat scroll 4px 5px;
padding-top: 5px;
padding-bottom: 5px;
}
li.logo > a > p {
font-size: 13px;
margin-bottom: 0;
color: #333333px;
}
.jstree-closed > a > i.jstree-checkbox,
.jstree-open > a > i.jstree-checkbox
{ display: none; }
.datatable-wrapper {
margin-bottom: 20px;
}
.faq-link > svg {
visibility: hidden;
}
+.time-selects {
+ width: 47%;
+ display: inline-block;
+}
+
h2:hover > a.faq-link > svg {
visibility: visible;
}
diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb
index 67fb13a..3855d09 100644
--- a/app/controllers/schedules_controller.rb
+++ b/app/controllers/schedules_controller.rb
@@ -1,84 +1,90 @@
class SchedulesController < ApplicationController
before_action :require_logged_in
before_action :fetch_host, only: [:new, :create, :show, :edit, :update]
before_action :fetch_job_id, only: [:new, :create, :show, :edit, :update]
before_action :fetch_schedule, only: [:show, :edit, :update]
# GET /hosts/:host_id/schedules/new
def new
@schedule = @host.schedules.new
@schedule.schedule_runs.build.default_run
end
# GET /hosts/:host_id/schedules/:id
def show
respond_to do |format|
format.js {}
end
end
# GET /hosts/:host_id/schedules/:id/edit
def edit
end
# PATCH /hosts/:host_id/schedules/:id
def update
if @schedule.update(fetch_params)
flash[:success] = 'Schedule updated successfully'
participating_hosts = @schedule.participating_hosts
if participating_hosts.size.nonzero?
participating_hosts.each(&:recalculate)
flash[:alert] = "You will need to redeploy the afffected clients: " +
participating_hosts.map(&:name).join(', ')
end
if @job_id
redirect_to edit_host_job_path(@host, @job_id, schedule_id: @schedule.id)
else
redirect_to new_host_job_path(@host, schedule_id: @schedule.id)
end
else
render :edit
end
end
# POST /hosts/:host_id/schedules
def create
@schedule = @host.schedules.new(fetch_params)
@schedule.runtime = params[:schedule][:runtime] if params[:schedule][:runtime]
if @schedule.save
flash[:success] = 'Schedule created successfully'
if @job_id.present?
redirect_to edit_host_job_path(@host, @job_id, schedule_id: @schedule.id)
else
redirect_to new_host_job_path(@host, schedule_id: @schedule.id)
end
else
render :new
end
end
# DELETE /hosts/:host_id/schedules/:id
def destroy
end
private
def fetch_schedule
@schedule = @host.schedules.find(params[:id])
end
def fetch_host
@host = current_user.hosts.find(params[:host_id])
end
def fetch_job_id
@job_id = @host.job_templates.find(params[:job_id]).id if params[:job_id].present?
end
def fetch_params
+ params[:schedule][:schedule_runs_attributes].each do |sched, attrs|
+ hour = attrs.delete('time_wrapper(4i)')
+ minute = attrs.delete('time_wrapper(5i)')
+ attrs[:time] = Time.new.change(hour: hour, min: minute).strftime('%H:%M')
+ params[:schedule][:schedule_runs_attributes][sched] = attrs
+ end
params.require(:schedule).
permit(:name, { schedule_runs_attributes: [[:id, :level, :month, :day, :time, :_destroy]] })
end
end
diff --git a/app/models/schedule_run.rb b/app/models/schedule_run.rb
index 0416838..1895d3e 100644
--- a/app/models/schedule_run.rb
+++ b/app/models/schedule_run.rb
@@ -1,164 +1,169 @@
# ScheduleRun is a helper class that modelizes the run directives of a schedule
# resource.
#
# It can have 3 levels:
#
# * full
# * differential
# * incremental
#
# Each ScheduleRun instance holds info about the execution time of the schedule:
#
# * month specification is optional and is described by:
# - month: full name (eg april) | month name three first letters (eg jul)
# - month_range: month-month
# - monthly: 'monthly'
# * day specification is required and is described by:
# - week_number (optional): weeks number in full text (eg: third, fourth)
# - week_range (optional): week_number-week_number
# - day: first three letters of day (eg: mon, fri)
# - day_range: day-day
# * time specification is required and is described by:
# - 24h time (eg: 03:00)
#
# Schedule Run examples:
#
# Level=Full monthly first mon at 12:21
# Level=Full first sun at 12:34
# Level=Differential second-fifth sat at 15:23
# Level=Incremental mon-sat at 08:00
class ScheduleRun < ActiveRecord::Base
establish_connection ARCHIVING_CONF
+ attr_accessor :time_wrapper
+
enum level: { full: 0, differential: 1, incremental: 2 }
MONTH_KW = %w{jan feb mar apr may jun jul aug sep oct nov dec january february march
april may june july august september october november december}
DAYS = (1..31).to_a
WDAY_KW = %w{mon tue wed thu fri sat sun}
WEEK_KW = %w{first second third fourth fifth}
belongs_to :schedule
validates :day, :time, :level, presence: true
validate :correct_chars
validate :month_valid, if: "month.present?"
validate :time_valid
validate :day_valid
def self.options_for_select
levels.keys.zip levels.keys
end
+ def time_wrapper
+ time.to_time
+ end
# Builds a sane default schedule_run
#
# @return [ScheduleRun]
def default_run
self.level = :full
self.day = "first sun"
self.time = '04:00'
end
# Composes the schedule line for the bacula configuration
#
# @return [String]
def schedule_line
[ level_to_config, pool_to_config, month, day, "at #{time}"].join(" ")
end
# Provides a human readable projection of the schedule run
#
# @return [String]
def human_readable
["#{level.capitalize} backup", month, day, "at #{time}"].join(' ')
end
private
def correct_chars
[:month, :day, :time].each do |x|
if self.send(x) && self.send(x).to_s.gsub(/[0-9a-zA-Z\-:,]/, '').present?
self.errors.add(x, 'Invalid characters')
end
end
end
def month_valid
if !month_format? && !valid_month_range?
self.errors.add(:month, 'Invalid month')
end
end
def month_format?
month_regex = "^(#{MONTH_KW.join('|')}|monthly)$"
month.match(month_regex).present?
end
def valid_month_range?
months = month.split('-')
return false if months.length != 2
MONTH_KW.index(months.last) % 12 - MONTH_KW.index(months.first) % 12 > 0
end
def time_valid
if !time.match(/^([01][0-9]|2[0-3]):[0-5][0-9]$/)
self.errors.add(:time, 'Invalid time')
end
end
def day_valid
components = day.split(' ')
if components.length < 1 || components.length > 2
self.errors.add(:day, 'Invalid day')
return false
end
if !valid_day?(components.last) && !valid_day_range?(components.last) &&
!valid_day_listing?(components.last)
self.errors.add(:day, 'Invalid day')
return false
end
if components.length == 2 && !valid_week?(components.first) &&
!valid_week_range?(components.first)
self.errors.add(:day, 'Invalid day')
return false
end
true
end
def valid_day_listing?(listing)
listing.split(',').all? { |d| WDAY_KW.include? d }
end
def valid_day?(a_day)
WDAY_KW.include? a_day
end
def valid_day_range?(a_range)
days = a_range.split('-')
return false if days.length != 2
WDAY_KW.index(days.last) - WDAY_KW.index(days.first) > 0
end
def valid_week?(a_week)
WEEK_KW.include? a_week
end
def valid_week_range?(a_range)
weeks = a_range.split('-')
return false if weeks.length != 2
WEEK_KW.index(weeks.last) - WEEK_KW.index(weeks.first) > 0
end
def level_to_config
"Level=#{level.capitalize}"
end
def pool_to_config
"Pool=#{ConfigurationSetting.current_pool_settings[level.to_sym]}"
end
end
diff --git a/app/views/schedules/_form.html.erb b/app/views/schedules/_form.html.erb
index 4c3700b..da86337 100644
--- a/app/views/schedules/_form.html.erb
+++ b/app/views/schedules/_form.html.erb
@@ -1,51 +1,59 @@
<div class="panel-body">
<%= bootstrap_form_for(@schedule, url: url, method: method, layout: :horizontal,
label_col: 'col-xs-3', control_col: 'col-xs-8') do |f| %>
<%= f.text_field :name, required: true %>
<hr />
<% if ['schedule_runs.day','schedule_runs.month','scheduled_runs.time'] - @schedule.errors.keys %>
<div id="error_explanation" class="has-error">
<ul>
<% @schedule.errors.full_messages.each do |message| %>
<li><span class="help-block"><%= message %></span></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.fields_for :schedule_runs, @schedule.schedule_runs do |r| %>
<div class="schedule_run_form">
<%= r.select :level, options_for_select(ScheduleRun.options_for_select, r.object.level) %>
<%= r.text_field :month, placeholder: '[month | month-range]' %>
<p class="col-xs-10 col-xs-offset-1 help-block text-right">eg: jan-mar, feb, monthly</p>
<%= r.text_field :day, placeholder: '[week | week-range] day | day-range',
required: true %>
<p class="col-xs-10 col-xs-offset-1 help-block text-right">
eg: first sun, second-fifth mon, mon-sat
</p>
- <%= r.text_field :time, placeholder: 'HH:MM', class: 'timepicker', required: true %>
+ <%= r.time_select :time_wrapper, { ignore_date: true, required: true, label: :Time },
+ { class: 'time-selects' } %>
<hr />
</div>
<% end %>
<div class="col-xs-1 col-xs-offset-10">
<%= link_to '#', class: 'schedule_run_form_remove', style: 'display:none;' do %>
<span class="glyphicon glyphicon-remove text-danger"></span>
<% end %>
</div>
<div class="col-xs-1 col-xs-offset-10">
<%= link_to '#', class: 'schedule_run_form_plus' do %>
<span class="glyphicon glyphicon-plus text-success"></span>
<% end %>
</div>
<%= (hidden_field_tag :job_id, @job_id) if @job_id %>
<div class="form-group">
- <div class="col-xs-offset-3 col-xs-8">
+ <div class="col-xs-offset-3 col-xs-4">
+ <%= link_to (@job_id.present? ? edit_host_job_path(@host, @job_id) : new_host_job_path(@host)), class: 'btn btn-default' do %>
+ <label class="glyphicon glyphicon-menu-left text-primary"></label>
+ Back to job
+ <% end %>
+ </div>
+
+ <div class="col-xs-4">
<%= f.submit class: 'btn btn-success' %>
</div>
</div>
<% end %>
</div>
diff --git a/app/views/schedules/_level_explanation.html.erb b/app/views/schedules/_level_explanation.html.erb
index 0bf6082..9b94613 100644
--- a/app/views/schedules/_level_explanation.html.erb
+++ b/app/views/schedules/_level_explanation.html.erb
@@ -1,31 +1,24 @@
<div class="col-xs-5">
<div class="row">
<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-heading">
<h4>Level Explanation</h4>
</div>
<br />
<div class="panel-body">
<h4>Full</h4>
<p> When the Level is set to Full all files in the FileSet whether or not they have changed will be backed up.</p>
<h4>Differential</h4>
<p>When the Level is set to Differential all files specified in the FileSet that have changed since the last successful Full backup of the same Job will be backed up.</p>
<p>If there is no successful previous Full backup, a Differential backup is upgraded to a Full backup.</p>
<h4>Incremental</h4>
<p>When the Level is set to Incremental all files specified in the FileSet that have changed since the last successful backup of the the same Job using the same FileSet and Client, will be backed up.<p>
<p>If there is no successful previous Full backup, an Incremental backup is upgraded to a Full backup.</p>
</div>
</div>
</div>
</div>
-
- <div class="row">
- <div class="col-xs-12">
- <%= link_to 'Back to job',
- @job_id.present? ? edit_host_job_path(@host, @job_id) : new_host_job_path(@host) %>
- </div>
- </div>
</div>

Event Timeline