__PACKAGE__->mk_accessors(
qw/root file comment parent/
);
sub
new {
my
$class
=
shift
;
my
$self
=
$class
->
next
::method(
@_
);
croak
"need full path to root"
if
!-d
$self
->root;
croak
"need full path to file"
if
!-e
$self
->file;
$self
->{root} =~ s{/+$}{};
$self
->{file} =~ s{/+$}{};
$self
->{root} =~ s{/+}{/}g;
$self
->{file} =~ s{/+}{/}g;
my
$file
=
$self
->file;
$self
->data(
scalar
read_file(
$file
));
my
$encoding
= get_attribute_recursively(
$file
,
$self
->root,
'encoding'
);
my
%attributes
= get_attributes (
$file
);
$attributes
{encoding} ||=
$encoding
;
map
{
delete
$attributes
{
$_
} }
grep
{ 1
if
!
defined
$attributes
{
$_
} }
keys
%attributes
;
my
(
undef
,
undef
,
$basename
) = File::Spec->splitpath(
$self
->file);
$self
->metadata ( {
%attributes
,
creation_time
=> creation_time(
$file
),
modification_time
=> (
stat
$file
)[9],
name
=>
$basename
,
} );
$self
->metadata->{comment_count} =
$self
->_child_count;
$self
->metadata->{path} =
$self
->id;
if
(
$self
->parent) {
$self
->metadata->{path} =
$self
->parent .
'/'
.
$self
->id;
}
$self
->{metadata}{type} ||=
$self
->{metadata}{name} =~ m{[.](\w+)$} ?
$1 :
'text'
;
$self
->{metadata}->{comment} =
defined
$self
->{comment} ? 1 : 0;
foreach
my
$t
(
grep
{/tags[.]\w+/}
keys
%{
$self
->{metadata}}) {
$t
=~ /tags[.](\w+)/;
my
$tag
=
lc
$1;
$self
->{metadata}{tags}{
$tag
} =
$self
->{metadata}{
$t
};
delete
$self
->{metadata}{
$t
};
}
return
$self
;
}
sub
store_attribute {
my
$self
=
shift
;
my
$attr
=
shift
;
my
$value
=
shift
;
set_attribute(
$self
->file,
$attr
,
$value
);
$self
->
next
::method(
$attr
,
$value
);
return
;
}
sub
store_data {
my
$self
=
shift
;
my
$data
=
shift
;
File::Slurp::write_file(
$self
->file,
$data
);
$self
->
next
::method(
$data
);
return
;
}
sub
children {
my
$self
=
shift
;
my
$kids
=
shift
;
if
(
defined
$kids
) {
return
$self
->{children} =
$kids
;
}
if
(!
$self
->{children}) {
$self
->{children} = [
$self
->_children];
}
return
$self
->{children};
}
sub
_get_commentdir {
my
$self
=
shift
;
my
$commentdir
;
my
(
undef
,
$container
,
undef
) = File::Spec->splitpath(
$self
->file);
$self
->{root} =~ s{/+$}{};
$container
=~ s{/+$}{};
if
(
$container
eq
$self
->root) {
$commentdir
=
"$container/.comments/"
.
$self
->id;
}
else
{
$commentdir
=
"$container/"
.
$self
->id;
}
mkpath(
$commentdir
);
return
$commentdir
;
}
sub
_children {
my
$self
=
shift
;
my
$commentdir
=
$self
->_get_commentdir();
opendir
my
$dir
,
$commentdir
or
die
"failed to open $commentdir: $!"
;
my
@result
=
map
{
my
$file
=
"$commentdir/$_"
;
Angerwhale::Content::Filesystem::Item->
new({
root
=>
$self
->root,
base
=>
$commentdir
,
file
=>
$file
,
comment
=> 1,
parent
=>
$self
->metadata->{path},
});
}
grep
{
$_
!~ /^[.]/ &&
!-d
"$commentdir/$_"
;
}
readdir
$dir
;
closedir
$dir
;
return
@result
;
}
sub
_child_count {
my
$self
=
shift
;
my
$count
= 0;
find(
sub
{
$count
++
if
-f
$File::Find::name
&&
$_
!~ /^[.]/;
},
$self
->_get_commentdir );
return
$count
;
}
sub
add_tag {
my
$self
=
shift
;
my
@tags
=
@_
;
foreach
my
$tag
(
@tags
){
$tag
=
lc
$tag
;
my
$count
=
$self
->metadata->{tags}{
$tag
} || 0;
$self
->store_attribute(
"tags.$tag"
, ++
$count
);
$self
->metadata->{tags}{
$tag
} =
$count
;
delete
$self
->metadata->{
"tags.$tag"
};
}
}
sub
add_comment {
my
$self
=
shift
;
my
$title
=
shift
;
my
$body
=
shift
;
my
$user
=
shift
;
my
$type
=
shift
;
croak
"no data to post"
if
( !
$title
|| !
$body
);
my
$comment_dir
=
$self
->_get_commentdir;
croak
"no comment dir $comment_dir"
if
!-d
$comment_dir
;
my
$safe_title
=
$title
;
$safe_title
=~ s{[^A-Za-z_]}{}g;
my
$filename
=
$comment_dir
.
"/$safe_title"
;
while
( -e
$filename
) {
$filename
.=
" ["
.
int
(
rand
(10000) ) .
"]"
;
}
my
$tmpname
=
$filename
;
$tmpname
=~ s{/([^/]+)$}{._tmp_.$1};
open
my
$comment
,
'>:raw'
,
$tmpname
or
die
"unable to open $filename: $!"
;
eval
{
my
$copy
=
"$body"
;
utf8::encode(
$copy
)
if
utf8::is_utf8(
$body
);
print
{
$comment
}
"$copy\n"
or
die
"io error: $!"
;
close
$comment
;
rename
(
$tmpname
=>
$filename
)
or
die
"Couldn't rename $tmpname to $filename: $!"
;
};
if
($@) {
close
$comment
;
unlink
$tmpname
;
unlink
$filename
;
die
$@;
}
eval
{
my
$comment
= Angerwhale::Content::Filesystem::Item->
new({
root
=>
$self
->root,
base
=>
$comment_dir
,
file
=>
$filename
,
comment
=> 1,
parent
=>
$self
->metadata->{path},
});
if
(
$user
) {
$comment
->store_attribute(
'author'
,
$user
);
}
$comment
->store_attribute(
'title'
,
$title
);
if
(
defined
$type
) {
$comment
->store_attribute(
'type'
,
$type
);
}
};
if
($@) {
unlink
$filename
;
die
"Problems seting attributes: $@"
;
}
return
$comment
;
}
1;