vortex_utils 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -0
- data/lib/vortex_utils/string_extensions.rb +83 -0
- data/lib/vortex_utils.rb +138 -0
- data/test/helper.rb +10 -0
- data/test/test_net_dav_extensions.rb +67 -0
- data/test/test_string_extensions.rb +18 -0
- metadata +88 -0
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'iconv'
|
3
|
+
|
4
|
+
# Utilities useful for adding content to Content Management Systems
|
5
|
+
|
6
|
+
class String
|
7
|
+
|
8
|
+
# Turn a normal sentence into a valid, readable filename.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# "A small test".to_readable_url
|
13
|
+
# => "a-small-test"
|
14
|
+
def to_readable_url
|
15
|
+
sentence = self
|
16
|
+
if(sentence.size > 10)then
|
17
|
+
truncated_title = sentence.sub(/:.*/,"").sub(/;/,"").sub(/&/,"").sub(/\(/,"").sub(/\)/,"")
|
18
|
+
html_filename = truncated_title.snake_case
|
19
|
+
else
|
20
|
+
html_filename = sentence.snake_case
|
21
|
+
end
|
22
|
+
|
23
|
+
# Just keep the 100 first chars, to nearest word.
|
24
|
+
if(html_filename.size > 100)then
|
25
|
+
html_filename = html_filename.gsub(/\.html$/,"")
|
26
|
+
html_filename = html_filename[0..100]
|
27
|
+
html_filename = html_filename.gsub(/_[^_]*$/,"") + ".html"
|
28
|
+
end
|
29
|
+
return html_filename
|
30
|
+
end
|
31
|
+
|
32
|
+
def snake_case
|
33
|
+
camel_cased_word_input = self
|
34
|
+
camel_cased_word = camel_cased_word_input + "" # create local copy of string
|
35
|
+
camel_cased_word = camel_cased_word.transliterate_accents
|
36
|
+
camel_cased_word = camel_cased_word.to_s.gsub(/::/, '/').
|
37
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1\2').
|
38
|
+
gsub(/([a-z\d])([A-Z])/,'\1\2').downcase
|
39
|
+
|
40
|
+
camel_cased_word = camel_cased_word.to_s.gsub(/ /,'-')
|
41
|
+
camel_cased_word = camel_cased_word.to_s.gsub(/^_/,'')
|
42
|
+
camel_cased_word = camel_cased_word.gsub("__","_")
|
43
|
+
|
44
|
+
# sanitize the string
|
45
|
+
camel_cased_word = camel_cased_word.gsub(/[^a-z._0-9 -]/i, "").
|
46
|
+
tr(".", "_").gsub(/(\s+)/, "_").gsub(/_/, '-').downcase
|
47
|
+
camel_cased_word = camel_cased_word.to_s.gsub(/--*/,'-')
|
48
|
+
return camel_cased_word
|
49
|
+
end
|
50
|
+
|
51
|
+
# Filter accents and some special characters
|
52
|
+
def transliterate_accents
|
53
|
+
str = self
|
54
|
+
accents = {
|
55
|
+
['á','à','â','ä','ã','Ã','Ä','Â','À'] => 'a',
|
56
|
+
['é','è','ê','ë','Ë','É','È','Ê'] => 'e',
|
57
|
+
['í','ì','î','ï','I','Î','Ì'] => 'i',
|
58
|
+
['ó','ò','ô','ö','õ','Õ','Ö','Ô','Ò'] => 'o',
|
59
|
+
['ñ'] => 'n',
|
60
|
+
['œ'] => 'e',
|
61
|
+
['ß'] => 'ss',
|
62
|
+
['ú','ù','û','ü','U','Û','Ù'] => 'u',
|
63
|
+
['æ'] => 'ae',
|
64
|
+
['ø'] => 'o',
|
65
|
+
['å'] => 'a',
|
66
|
+
['Æ'] => 'ae',
|
67
|
+
['Ø'] => 'o',
|
68
|
+
['Å'] => 'a',
|
69
|
+
['§'] => ''
|
70
|
+
}
|
71
|
+
accents.each do |ac,rep|
|
72
|
+
ac.each do |s|
|
73
|
+
str.gsub!(s, rep)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Remove the rest of the accents and special characters
|
78
|
+
conv = Iconv.new("ASCII//TRANSLIT//IGNORE", "UTF-8")
|
79
|
+
str = conv.iconv(str)
|
80
|
+
return str
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
data/lib/vortex_utils.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require_relative 'vortex_utils/string_extensions'
|
2
|
+
|
3
|
+
# Utilites used to access the Vortex CMS from the WebDAV protocol and do common tasks
|
4
|
+
|
5
|
+
require 'net/dav'
|
6
|
+
require 'uri'
|
7
|
+
require 'highline/import'
|
8
|
+
require 'time'
|
9
|
+
require 'json'
|
10
|
+
|
11
|
+
module Net
|
12
|
+
|
13
|
+
class DAV
|
14
|
+
|
15
|
+
def initialize(uri, *args)
|
16
|
+
@uri = uri
|
17
|
+
@uri = URI.parse(@uri) if @uri.is_a? String
|
18
|
+
@have_curl = false # This defaults to true in Net::DAV
|
19
|
+
@handler = NetHttpHandler.new(@uri)
|
20
|
+
@handler.verify_server = false # This defaults to true in Net::DAV
|
21
|
+
if(args != [])
|
22
|
+
if(args[0][:use_osx_keychain] or args[0][:osx_keychain])then
|
23
|
+
|
24
|
+
# Retrieve password from OS X KeyChain.
|
25
|
+
osx = (RUBY_PLATFORM =~ /darwin/)
|
26
|
+
if(osx)then
|
27
|
+
require 'osx_keychain'
|
28
|
+
keychain = OSXKeychain.new
|
29
|
+
user = ENV['USER']
|
30
|
+
|
31
|
+
if(args[0][:prompt_for_password])
|
32
|
+
response = `security delete-generic-password -s #{@uri.host}`
|
33
|
+
require 'pry'
|
34
|
+
binding.pry
|
35
|
+
end
|
36
|
+
|
37
|
+
pass = keychain[@uri.host, user ]
|
38
|
+
|
39
|
+
if(pass == nil) then
|
40
|
+
puts "Password not found on OS X KeyChain. "
|
41
|
+
puts "Enter password to store new password on OS X KeyChain."
|
42
|
+
## @handler.user = ask("Username: ") {|q| q.echo = true}
|
43
|
+
## Todo: store username in a config file so we can have
|
44
|
+
## different username locally and on server
|
45
|
+
pass = ask("Password: ") {|q| q.echo = "*"} # false => no echo
|
46
|
+
keychain[@uri.host, user] = pass
|
47
|
+
puts "Password for '#{user}' on '#{@uri.host}' stored on OS X KeyChain."
|
48
|
+
@handler.user = user
|
49
|
+
@handler.pass = pass
|
50
|
+
else
|
51
|
+
@handler.user = user
|
52
|
+
@handler.pass = pass
|
53
|
+
end
|
54
|
+
return @handler
|
55
|
+
|
56
|
+
else
|
57
|
+
puts "Warning: Not running on OS X."
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
@handler.user = args[0]
|
62
|
+
@handler.pass = args[1]
|
63
|
+
else
|
64
|
+
@handler.user = ask("Username: ") {|q| q.echo = true}
|
65
|
+
@handler.pass = ask("Password: ") {|q| q.echo = "*"} # false => no echo
|
66
|
+
end
|
67
|
+
return @handler
|
68
|
+
end
|
69
|
+
|
70
|
+
# Set the publish date to current timestamp
|
71
|
+
def vortex_publish!(uri)
|
72
|
+
proppatch(uri, '<v:publish-date xmlns:v="vrtx">' + Time.now.httpdate.to_s + '</v:publish-date>')
|
73
|
+
end
|
74
|
+
|
75
|
+
def vortex_publish(uri,time)
|
76
|
+
proppatch(uri, '<v:publish-date xmlns:v="vrtx">' + time.httpdate.to_s + '</v:publish-date>')
|
77
|
+
end
|
78
|
+
|
79
|
+
def vortex_unpublish!(uri)
|
80
|
+
proppatch(uri, '<v:unpublish-date xmlns:v="vrtx">' +Time.now.httpdate.to_s + '</v:unpublish-date>')
|
81
|
+
end
|
82
|
+
|
83
|
+
def vortex_unpublish(uri, time)
|
84
|
+
proppatch(uri, '<v:unpublish-date xmlns:v="vrtx">' + time.httpdate.to_s + '</v:unpublish-date>')
|
85
|
+
end
|
86
|
+
|
87
|
+
# Create path - create all folders in the given path if they do not exist.
|
88
|
+
#
|
89
|
+
# Default is article-listing folder and the foldername used as title.
|
90
|
+
#
|
91
|
+
# Example:
|
92
|
+
#
|
93
|
+
# create_path('/folders/to/be/created/')
|
94
|
+
# create_path('/folders/to/be/created/', :type => "event-listing", :title => "Testing")
|
95
|
+
def create_path(dest_path, *args)
|
96
|
+
title = nil
|
97
|
+
if(args.size > 0)then
|
98
|
+
type = args[0][:type]
|
99
|
+
title = args[0][:title]
|
100
|
+
end
|
101
|
+
if(not(type))then
|
102
|
+
type = "article-listing"
|
103
|
+
end
|
104
|
+
|
105
|
+
destination_path = "/"
|
106
|
+
dest_path.split("/").each do |folder|
|
107
|
+
if(folder != "")then
|
108
|
+
folder = folder.downcase
|
109
|
+
destination_path = destination_path + folder + "/"
|
110
|
+
if( not(exists?(destination_path)) )then
|
111
|
+
mkdir(destination_path)
|
112
|
+
proppatch(destination_path,'<v:collection-type xmlns:v="vrtx">' + type + '</v:collection-type>')
|
113
|
+
if(title)then
|
114
|
+
proppatch(destination_path,'<v:userTitle xmlns:v="vrtx">' + title.to_s + '</v:userTitle>')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
return destination_path
|
120
|
+
end
|
121
|
+
|
122
|
+
def set_vortex_collection_title(uri, title)
|
123
|
+
proppatch(uri,'<v:userTitle xmlns:v="vrtx">' + title.to_s + '</v:userTitle>')
|
124
|
+
end
|
125
|
+
|
126
|
+
def set_vortex_collection_type(uri, type)
|
127
|
+
proppatch(uri,'<v:collection-type xmlns:v="vrtx">' + type + '</v:collection-type>')
|
128
|
+
end
|
129
|
+
|
130
|
+
def hide_vortex_collection(uri)
|
131
|
+
proppatch(uri, '<hidden xmlns="http://www.uio.no/navigation">true</hidden>')
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
end
|
138
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative 'helper'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class NetDAVExtensions < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
uri = 'https://www-dav.usit.uio.no/om/organisasjon/web/wapp/ansatte/thomasfl/vortex-script/test/'
|
9
|
+
@dav = Net::DAV.new(uri,:osx_keychain => true)
|
10
|
+
end
|
11
|
+
|
12
|
+
should "delete password from keychain and prompt for password" do
|
13
|
+
# dav = Net::DAV.new("https://www-dav.usit.uio.no/om/organisasjon/web/wapp/ansatte/thomasfl/vortex-script/test/",
|
14
|
+
# :osx_keychain => true, :prompt_for_password => true)
|
15
|
+
end
|
16
|
+
|
17
|
+
should "publish article" do
|
18
|
+
tittel = "My little testing article ÆØÅ"
|
19
|
+
|
20
|
+
article = {
|
21
|
+
"resourcetype" => "structured-article",
|
22
|
+
"properties" => {
|
23
|
+
"title" => tittel,
|
24
|
+
"introduction" => "Dette er innledningen til artikkelen",
|
25
|
+
"content" => "<p>Her er innholdet i artikkelen</p>"
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
filename = tittel.to_readable_url + '.html'
|
30
|
+
@dav.put_string(filename, article.to_json)
|
31
|
+
@dav.vortex_publish!(filename)
|
32
|
+
assert @dav.exists?(filename)
|
33
|
+
end
|
34
|
+
|
35
|
+
should "set publish date to 2 days ahead and unpublish date to 3 days" do
|
36
|
+
article = {
|
37
|
+
"resourcetype" => "structured-article",
|
38
|
+
"properties" => {
|
39
|
+
"title" => "Test article",
|
40
|
+
"introduction" => "Dette er innledningen til artikkelen",
|
41
|
+
"content" => "<p>Her er innholdet i artikkelen</p>"
|
42
|
+
}
|
43
|
+
}
|
44
|
+
@dav.put_string('test-article.html', article.to_json)
|
45
|
+
@dav.vortex_publish('test-article.html', Time.now + (2*24*60*60))
|
46
|
+
@dav.vortex_unpublish('test-article.html', Time.now + (3*24*60*60))
|
47
|
+
end
|
48
|
+
|
49
|
+
should "create paths and set type" do
|
50
|
+
path = '/om/organisasjon/web/wapp/ansatte/thomasfl/vortex-script/test/'
|
51
|
+
@dav.create_path(path + 'folders/to/be/created', :type => "article-listing")
|
52
|
+
assert(@dav.exists?(path + 'folders/to/be/created'))
|
53
|
+
@dav.delete(path + 'folders')
|
54
|
+
assert( !@dav.exists?(path + 'folders') )
|
55
|
+
|
56
|
+
folder_path = path + 'test_folder'
|
57
|
+
if(@dav.exists?(folder_path))
|
58
|
+
@dav.delete(folder_path)
|
59
|
+
end
|
60
|
+
@dav.mkdir(folder_path)
|
61
|
+
@dav.set_vortex_collection_title(folder_path,'En tittel')
|
62
|
+
@dav.set_vortex_collection_type(folder_path,'article-listing')
|
63
|
+
@dav.hide_vortex_collection(folder_path)
|
64
|
+
@dav.delete(folder_path)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative 'helper'
|
3
|
+
|
4
|
+
class TestStringExtensions < Test::Unit::TestCase
|
5
|
+
|
6
|
+
should "transliterate accents nicesly" do
|
7
|
+
assert "ñâñôñä".transliterate_accents == "nanona"
|
8
|
+
end
|
9
|
+
|
10
|
+
should "snake case sentences" do
|
11
|
+
assert "one two three".snake_case == "one-two-three"
|
12
|
+
end
|
13
|
+
|
14
|
+
should "make sentences into strings usable for readable urls" do
|
15
|
+
assert "this is a çircûmflexed senteñce".to_readable_url == "this-is-a-circumflexed-sentence"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vortex_utils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas Flemming
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-01 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: net_dav
|
16
|
+
requirement: &2156218200 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2156218200
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: highline
|
27
|
+
requirement: &2156217040 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.6.9
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2156217040
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: thoughtbot-shoulda
|
38
|
+
requirement: &2156215100 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.11.1
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2156215100
|
47
|
+
description: Utilities for managing content on Vortex web content management system
|
48
|
+
through webdav
|
49
|
+
email: thomas.flemming@usit.uio.no
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- VERSION
|
55
|
+
- lib/vortex_utils.rb
|
56
|
+
- lib/vortex_utils/string_extensions.rb
|
57
|
+
- test/helper.rb
|
58
|
+
- test/test_net_dav_extensions.rb
|
59
|
+
- test/test_string_extensions.rb
|
60
|
+
homepage: http://github.com/thomasfl/vortex_utils
|
61
|
+
licenses: []
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options:
|
64
|
+
- --charset=UTF-8
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ! '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.8.10
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: Vortex CMS utilites
|
85
|
+
test_files:
|
86
|
+
- test/helper.rb
|
87
|
+
- test/test_net_dav_extensions.rb
|
88
|
+
- test/test_string_extensions.rb
|