kalindar 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjgyYTE3M2NkOTJiODk5NTcxNTkyZjFkODA4NTMyNDlkZmQ3NGFmMw==
5
+ data.tar.gz: !binary |-
6
+ YzMyYzI1NTVmNWMyODUxZjljMWRmZjU0NmM5MWFlZTg3ZjM1NzVlMQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MzNjNDFkNzYzM2EyOTgyODIwMTk5MTkzNDEyNzBhNDc2NWYxODQzZWQ4YTE1
10
+ ZjgxNjQ2YTk2OTRkN2M3MjZmNjFiNzI0NGMxNDhjYzM3YjY1Zjk4ZjNmYzY0
11
+ YTQwNjQxYTU3YjIzNDA5MzMzZjRhNmJkOTkxZDNmYWM4NTY2M2U=
12
+ data.tar.gz: !binary |-
13
+ OTI4MjAyYzYwOWQ3ZTgzMGZkZGZjNzBjMzQzNzk2MzY4ZTM1OWFiNTNjNzA0
14
+ ZDc4Y2E4N2ZhZTc0OWMzMDcyOWUzYWYzYTMxMzkwZWM0OTJkNTZmNDBiNzlj
15
+ MTVlNGVkZmVkZDhhYTA2Zjg5NWQ5YTNiYzFmMDdkMjFlOTBhMWU=
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ *.swp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kalindar.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Felix Wolfsteller
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Kalindar
2
+
3
+ Kalindar lets you view ics files via a webbrowser.
4
+
5
+ It employs the ri_cal, sinatra, i18n ruby gems, the rightjs JavaScript framework and the Pure CSS framework.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'kalindar'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install kalindar
20
+
21
+ ## Usage
22
+
23
+ bundle exec rackup
24
+
25
+ ## Naming
26
+
27
+ Kali is an Indian goddess of destruction, change and ... time .
28
+
29
+ ## Caveats
30
+
31
+ Be careful. Kalindar might destroy, change or delete your ics file(s)!
32
+
33
+ Kalindar does not care about timezones!
34
+
35
+ Kalindar gets confused by re-occuring events!
36
+
37
+ ### Configuration
38
+
39
+ Configuration is done in config.json . There one or many calendar (ics) files and the locale can be set.
40
+
41
+ ## Contributing
42
+
43
+ 0. Get in touch with me.
44
+ 1. Fork it ( https://github.com/[my-github-username]/kalindar/fork )
45
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
46
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
47
+ 4. Push to the branch (`git push origin my-new-feature`)
48
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
data/config.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ // Configuration file for kalindar - web frontend to view ics files.
3
+ // In JSON format.
4
+
5
+ // Specify one or more ics files.
6
+ // You can skip the list (['one.ics', 'two.ics']) syntax for single ones.
7
+ // The first calender is the one to be edited.
8
+ "calendar_files": "kalindar.ics",
9
+
10
+ // Specify the locale (currently 'de' or 'en').
11
+ "locale": "de"
12
+ }
data/config.ru ADDED
@@ -0,0 +1,2 @@
1
+ require 'kalindar'
2
+ run KalindarApp
data/kalindar.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kalindar/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kalindar"
8
+ spec.version = Kalindar::VERSION
9
+ spec.authors = ["Felix Wolfsteller"]
10
+ spec.email = ["felix.wolfsteller@gmail.com"]
11
+ spec.summary = %q{Web-Interface to ics files}
12
+ spec.description = %q{Web-Interface to ics files with sinatra}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "ri_cal", "~> 0.8"
22
+ spec.add_dependency "sinatra", "~> 1.4"
23
+ spec.add_dependency "slim", "~> 2.0"
24
+ spec.add_dependency "i18n", "~> 0.6"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.6"
27
+ spec.add_development_dependency "rake"
28
+ spec.add_development_dependency "rspec"
29
+ end
data/lib/kalindar.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "kalindar/version"
2
+ require 'kalindar/event_calendar'
3
+ require 'kalindar/app'
4
+ require 'kalindar/event'
5
+
6
+ module Kalindar
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,100 @@
1
+ require 'sinatra/base'
2
+ require 'slim'
3
+ require 'time'
4
+ require 'json'
5
+ require 'i18n'
6
+ require 'i18n/backend/fallbacks'
7
+
8
+ class KalindarApp < Sinatra::Base
9
+ $conf = JSON.load(File.new('config.json'))
10
+ $cal = EventCalendar.new($conf['calendar_files'])
11
+
12
+ configure do
13
+ I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
14
+ I18n.load_path = Dir[File.join(settings.root, 'locales', '*.yml')]
15
+ I18n.backend.load_translations
16
+ I18n.default_locale = $conf['locale'].to_sym
17
+ end
18
+
19
+ # Will use http-verb PUT
20
+ enable :method_override
21
+
22
+ # We like pretty html indentation
23
+ set :slim, :pretty => true
24
+
25
+ helpers do
26
+ def li_day_class day
27
+ return "sunday" if day.sunday?
28
+ return "saturday" if day.saturday?
29
+ "day"
30
+ end
31
+ def t(*args)
32
+ I18n.t(*args)
33
+ end
34
+ def l(*args)
35
+ I18n.l(*args)
36
+ end
37
+ end
38
+
39
+ get '/' do
40
+ redirect '/events'
41
+ end
42
+
43
+ get '/events' do
44
+ @events = {}
45
+ # events from today to in 30 days
46
+ (DateTime.now .. DateTime.now + 30).each do |day|
47
+ #@events[d] = $cal.events_for(d)
48
+ @events[day] = $cal.find_events day.to_date
49
+ end
50
+ slim :event_list
51
+ end
52
+
53
+ # Create DateTime from yyyymmdd + h + m .
54
+ def start_time_from_params params
55
+ hour = params['start_time'][/\d\d/].to_i
56
+ minute = params['start_time'][/:\d\d/][1,2].to_i
57
+ start_day = Date.parse(params['start_day'])
58
+ start_time = DateTime.new(start_day.year,
59
+ start_day.month, start_day.day, hour, minute)
60
+ end
61
+
62
+ # Adds minutes to start_time.
63
+ def end_time_from_params params, start_time
64
+ minutes = case params['duration']
65
+ when '15m' then 15
66
+ when '30m' then 30
67
+ when '60m' then 60
68
+ when '90m' then 90
69
+ when '120m' then 120
70
+ when '1d' then 24 * 60
71
+ when '2d' then 24 * 2 * 60
72
+ when '5d' then 24 * 5 * 60
73
+ when '1w' then 24 * 7 * 60
74
+ end
75
+ start_time + Rational(minutes, 1440)
76
+ end
77
+
78
+ # Add event, save ics file.
79
+ put '/event' do
80
+ event = RiCal::Component::Event.new($cal.calendars.first)
81
+ start_time = start_time_from_params params
82
+ event.dtstart = start_time
83
+ event.dtend = end_time_from_params params, start_time
84
+ event.summary = params['summary']
85
+ event.description = params['description']
86
+ event.location = params['location']
87
+
88
+ # Motivate Calendar Delegate
89
+ $cal.calendars.first.events << event
90
+ io = File.open($cal.filename_of($cal.calendars.first), 'w')
91
+ $cal.calendars.first.export_to io
92
+ io.close
93
+
94
+ redirect back
95
+ end
96
+
97
+ get '/event/new/:day' do
98
+ slim :new_event, :locals => {'start_date' => nil}
99
+ end
100
+ end
@@ -0,0 +1,24 @@
1
+ # Delegator with some handy shortcuts
2
+ class Event < SimpleDelegator
3
+ def start_time_f day
4
+ puts "start #{start_time} : #{start_time.class} #{start_time.to_date} #{day}"
5
+ return start_time.strftime('%H:%M') if start_time.to_date == day.to_date
6
+ return "..."
7
+ end
8
+ def finish_time_f day
9
+ return finish_time.strftime('%H:%M') if finish_time.to_date == day.to_date
10
+ return "..."
11
+ end
12
+ def time_f day
13
+ start = start_time_f day
14
+ finish = finish_time_f day
15
+ if start == finish && start == "..."
16
+ "..."
17
+ else
18
+ "#{start_time_f day} - #{finish_time_f day}"
19
+ end
20
+ end
21
+ def from_to_f
22
+ return "#{dtstart.to_datetime.strftime("%d.%m. %H:%M")} - #{dtend.to_datetime.strftime("%d.%m. %H:%M")}"
23
+ end
24
+ end
@@ -0,0 +1,103 @@
1
+ require 'ri_cal'
2
+
3
+ class EventCalendar
4
+ attr_accessor :calendars
5
+ attr_accessor :filenames # decorator?
6
+ # also decoreate event for access to calendar?
7
+
8
+ def initialize filename
9
+ @calendars = []
10
+ @filenames = []
11
+ if filename.class == Array
12
+ filename.each {|file| read_file file}
13
+ else
14
+ read_file filename
15
+ end
16
+ end
17
+
18
+ def read_file filename
19
+ @calendars << File.open(filename, 'r') do |file|
20
+ RiCal.parse file
21
+ end.flatten
22
+ # attention if more than one calendar in file!
23
+ @filenames << filename
24
+ @calendars.flatten!
25
+ end
26
+
27
+ # Catches only certain events
28
+ def singular_events_for_month year, month
29
+ @calendar.map do |calendar|
30
+ calendar.events.select { |event|
31
+ event_between? event, dtmonth_start(year, month), dtmonth_end(year, month)
32
+ }
33
+ end.flatten
34
+ end
35
+
36
+ def events_for_date date
37
+ events = @calendars.map &:events
38
+ events.select {|event| event_includes? event, date}.flatten
39
+ events.map {|event|
40
+ Event.new event
41
+ }
42
+ end
43
+
44
+ # Nother optimization potential
45
+ def events_per_day start_date, end_date
46
+ map = {}
47
+ (start_date .. end_date).each do |day|
48
+ (map[day] ||= []) << find_events(day)
49
+ end
50
+ map
51
+ end
52
+
53
+ # Best optimization potential
54
+ def events_in start_date, end_date
55
+ events = []
56
+ (start_date .. end_date).each do |day|
57
+ events << find_events(day)
58
+ end
59
+ events.flatten
60
+ end
61
+
62
+ def find_events date
63
+ #events = @calendars.map &:events
64
+ @calendars.map do |calendar|
65
+ calendar.events.select { |event|
66
+ event.dtstart.to_date == date || event.dtend.to_date == date ||!event.occurrences(:overlapping => [date, date +1]).empty?
67
+ }
68
+ end.flatten.map do |event|
69
+ Event.new event
70
+ end
71
+ end
72
+
73
+ def filename_of calendar
74
+ @filenames[@calendars.index calendar]
75
+ end
76
+
77
+ private
78
+
79
+ def dtmonth_start year, month
80
+ Icalendar::Values::Date.new('20101001')#"#{year}%02d%02d"%[month,01])
81
+ end
82
+
83
+ def dtmonth_end year, month
84
+ puts "last date for #{year} - #{month}"
85
+ last_day = Date.civil(year, month, -1)
86
+ Icalendar::Values::Date.new('20120102')#"#{year}#{month}#{last_day}")
87
+ end
88
+
89
+ def date_between? date, start_date, end_date
90
+ puts "d #{date} st #{start_date} e #{end_date}"
91
+ date > start_date && date < end_date
92
+ end
93
+
94
+ def event_between? event, start_date, end_date
95
+ event.dtstart.class == event.dtend.class && event.dtstart.class == Icalendar::Values::DateTime && (date_between?(event.dtstart, start_date, end_date) || date_between?(event.dtend, start_date, end_date))
96
+ end
97
+
98
+ def event_includes? event, date
99
+ event.dtstart.class == event.dtend.class && event.dtstart.class == Icalendar::Values::DateTime && (date_between?(date, event.dtstart, event.dtend))
100
+ end
101
+ end
102
+
103
+
@@ -0,0 +1,24 @@
1
+ de:
2
+ create_event: "Neuer Termin"
3
+ new_event: "Neuer Termin"
4
+ start_date: "Anfangsdatum"
5
+ when: "Uhrzeit"
6
+ summary: "Titel"
7
+ location: "Ort"
8
+ description: "Beschreibung"
9
+ duration: "Dauer"
10
+ event: "Termin"
11
+ 15m: "15 Minuten"
12
+ 30m: "30 Minuten"
13
+ 60m: "60 Minuten"
14
+ 90m: "90 Minuten"
15
+ 120m: "2 Stunden"
16
+ whole_day: "Ganztags"
17
+ 1d: "1 Tag"
18
+ 2d: "2 Tage"
19
+ 5d: "5 Tage"
20
+ 1w: "eine Woche"
21
+ save: "speichern"
22
+ time:
23
+ formats:
24
+ short: "%d.%m.%Y"