Skip to content

Commit

Permalink
Implemented backend to create new files
Browse files Browse the repository at this point in the history
  • Loading branch information
melmothx committed Mar 26, 2014
1 parent 012a041 commit 6985bd4
Show file tree
Hide file tree
Showing 9 changed files with 378 additions and 12 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ xapian/*
dbic.yaml
root/static/js/ckeditor*
specials/0blog0/*
staging/*
!staging/README.txt
*~

1 change: 1 addition & 0 deletions Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ requires 'Catalyst::Model::Adaptor';
# our own dogfood
requires 'Text::Amuse' => 0.11;
requires 'Text::Amuse::Compile' => 0.09;
requires 'Text::Amuse::Preprocessor' => 0.04;

# devel things to be removed at the end of the development cycle
# requires 'Catalyst::Plugin::StackTrace';
Expand Down
201 changes: 201 additions & 0 deletions lib/AmuseWikiFarm/Archive/Edit.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
package AmuseWikiFarm::Archive::Edit;

use strict;
use warnings;
use utf8;

use Moose;
use namespace::autoclean;

use File::Spec;
use File::Basename qw/basename/;
use Cwd;
use Data::Dumper;
use Date::Parse;
use DateTime;

use Text::Amuse;
use Text::Amuse::Preprocessor::HTML qw/html_to_muse/;
use AmuseWikiFarm::Utils::Amuse qw/muse_naming_algo/;

=head1 SYNOPSIS
This class must B<not> be reusued. Create in one request and throw it
away.
=cut

has site_schema => (is => 'ro',
required => 1,
isa => 'Object');

has basedir => (is => 'ro',
required => 1,
default => sub { getcwd },
isa => 'Str');

has error => (is => 'rw',
isa => 'Str');

has redirect => (is => 'rw',
isa => 'Str');

sub staging_dirname {
return 'staging';
}

sub staging_dir {
my $self = shift;
return File::Spec->catdir($self->basedir, $self->staging_dirname);
}

sub create_new {
my ($self, $params) = @_;

# assert that the directory where to put the files exists
my $staging_dir = $self->staging_dir;
unless (-d $staging_dir) {
mkdir $self->staging_dir or die "Couldn't create $staging_dir $!";
}

# URI generation
my $author = $params->{author} || "";
my $title = $params->{title} || "";
my $uri;
if ($params->{uri}) {
$uri = muse_naming_algo($params->{uri});
# replace the params with our clean form
}
elsif ($title) {
$uri = muse_naming_algo("$author $title");
}
unless ($uri) {
$self->error("Couldn't generate the uri!");
return;
}
# and store it in the params
$params->{uri} = $uri;


# check if the uri already exists. If so, throw an error and set
# the redirection.

my $exists = $self->site_schema->titles->find({ uri => $uri });
if ($exists) {
$self->error("Such an uri already exists");
$self->redirect($exists->uri);
return;
}
else {
return $self->import_text_from_html_params($params);
}
}

sub import_text_from_html_params {
my ($self, $params) = @_;
my $uri = $params->{uri};
die "uri not set!" unless $uri;

# the first thing we do is to assing a path and create a revision in the db
my $pubdate = str2time($params->{pubdate}) || time();
my $pubdt = DateTime->from_epoch(epoch => $pubdate);
$params->{pubdate} = $pubdt->iso8601;

# documented in Result::Title
my $bogus = {
uri => $uri,
pubdate => $pubdate,
f_suffix => '.muse',
status => 'editing',
};

foreach my $f (qw/f_path f_archive_rel_path f_timestamp
f_full_path_name f_name/) {
$bogus->{$f} = '';
}

my $title = $self->site_schema->titles->create($bogus);


# where to store the text. But we need to know which id we have in
# advance, so first set f_path to the empty string.

my $revision = $title->revisions->create({
updated => DateTime->now,
});

$self->revision_set_file_path($revision);

my $file = $revision->f_full_path_name;
die "full path was not set!" unless $file;

# populate the file with the parameters
open (my $fh, '>:encoding(utf-8)', $file) or die "Couldn't open $file $!";
# TODO add support for uid and cat (ATR)
foreach my $directive (qw/title subtitle author LISTtitle SORTauthors
SORTtopics date
source lang pubdate/) {

$self->_add_directive($fh, $directive, $params->{$directive});
}
# add the notes
$self->_add_directive($fh, notes => html_to_muse($params->{notes}));

# separator
print $fh "\n";

my $body = html_to_muse($params->{textbody});
if (defined $body) {
print $fh $body;
}
print $fh "\n\n";
close $fh or die $!;
return $revision;
}

sub _add_directive {
my ($self, $fh, $directive, $text) = @_;
die unless $fh && $directive;
return unless defined $text;
# usual washing
$text =~ s/\r*\n/ /gs; # it's a directive, no \n
# leading and trailing spaces
$text =~ s/^\s*//s;
$text =~ s/\s+$//s;
$text =~ s/ +/ /gs; # pack the whitespaces
return unless length($text);
print $fh '#' . $directive . ' ' . $text . "\n";
}

sub revision_set_file_path {
my ($self, $revision) = @_;
die "Bad usage, missing argument (revision row)" unless $revision;

my $uri = $revision->title->uri;
die "Couldn't find uri for belonging title!" unless $uri;

# the root
my $target_dir = File::Spec->catdir($self->staging_dir, $revision->id);
if (-d $target_dir) {
# mm, some db backend is reusing the ids, so clean it up
opendir(my $dh, $target_dir) or die "Can't open dir $target_dir $!";
my @cleanup = grep {
-f File::Spec->catfile($target_dir, $_)
} readdir($dh);
closedir $dh;
foreach my $clean (@cleanup) {
warn "Removing $clean in $target_dir";
unlink File::Spec->catfile($target_dir, $clean) or warn $!;
}
}
else {
mkdir $target_dir or die "Couldn't create $target_dir $!";
}
my $fullpath = File::Spec->catfile($target_dir, $uri . '.muse');
$revision->f_full_path_name($fullpath);
}


__PACKAGE__->meta->make_immutable;

1;
29 changes: 22 additions & 7 deletions lib/AmuseWikiFarm/Schema/Result/Revision.pm
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ __PACKAGE__->table("revision");
is_foreign_key: 1
is_nullable: 1
=head2 f_path
=head2 f_full_path_name
data_type: 'text'
is_nullable: 0
is_nullable: 1
=head2 updated
Expand All @@ -76,8 +76,8 @@ __PACKAGE__->add_columns(
{ data_type => "varchar", is_foreign_key => 1, is_nullable => 1, size => 8 },
"title_id",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
"f_path",
{ data_type => "text", is_nullable => 0 },
"f_full_path_name",
{ data_type => "text", is_nullable => 1 },
"updated",
{ data_type => "datetime", is_nullable => 0 },
);
Expand Down Expand Up @@ -137,10 +137,25 @@ __PACKAGE__->belongs_to(
);


# Created by DBIx::Class::Schema::Loader v0.07039 @ 2014-03-26 08:29:59
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:AEgqv+Ctiw6Tr5VUFNXaAQ
# Created by DBIx::Class::Schema::Loader v0.07039 @ 2014-03-26 12:38:38
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:+kcdIGDZPSeRauslB6tq6A

use File::Slurp;

=head2 muse_body
Return the text stored in the staging area (for editing)
=cut

sub muse_body {
my $self = shift;
my $file = $self->f_full_path_name;
return '' unless -f $file;
return read_file($file => { binmode => ':encoding(UTF-8)' });
}



# You can replace this text with custom code or comments, and it will be preserved on regeneration
__PACKAGE__->meta->make_immutable;
1;
32 changes: 31 additions & 1 deletion lib/AmuseWikiFarm/Schema/Result/Title.pm
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,37 @@ sub category_listing {
Logic to determine if a file is published or not. These routine should
be called on indexing, not on searching, because they depend on the
current datetime.
current datetime. Only texts with a C<published> status should be
served directly.
Recognized statuses:
=over 4
=item unpublished
Default status.
=item deleted
File has been deleted
=item deferred
File has a publishing date in the future
=item published
File is up and running
=item editing
File is stashed in the staging area and should not be served. It will
have some revisions attached. The only real things set here are uri
and id. Everything else is bogus, and is used only to hook the
revisions, and prevent duplications and such.
=back
=head3 is_published
Expand Down
12 changes: 10 additions & 2 deletions root/src/edit/create.tt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ var ckconfiguration = {

<form id="ckform" action="[%- form_action -%]" method="post"
enctype="multipart/form-data">
<fieldset>
<label for="uri">
<strong>[% c.loc('Desired URI') %]</strong>
([% c.loc('automatically generated if not present') %])
</label>
<input type="text" name="uri" id="uri" size="50"
value="[% c.req.params.uri %]"/>
</fieldset>
<fieldset>
<p><label><em>Author</em> (for display):<br />
<input type="text" name="author" id="author"
Expand Down Expand Up @@ -134,7 +142,7 @@ var ckconfiguration = {
</div>
<div>&nbsp;</div>
<div>
<textarea id="maineditor" name="maineditor" cols="80"
<textarea id="textbody" name="textbody" cols="80"
rows="20">[%- c.req.params.maineditor | html -%]</textarea>
</div>

Expand Down Expand Up @@ -172,7 +180,7 @@ var ckconfiguration = {
</form>

<script type="text/javascript">
$('#maineditor').ckeditor(ckconfiguration);
$('#textbody).ckeditor(ckconfiguration);
ckconfiguration.height = 100;
$('#notes').ckeditor(ckconfiguration);
</script>
4 changes: 2 additions & 2 deletions sql/sqlite.sql
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ CREATE TABLE site (


CREATE TABLE revision (
id INTEGER PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
site_id VARCHAR(8) REFERENCES site(id)
ON DELETE CASCADE ON UPDATE CASCADE,
title_id INTEGER REFERENCES title(id)
ON DELETE CASCADE ON UPDATE CASCADE,
f_path TEXT NOT NULL,
f_full_path_name TEXT,
updated DATETIME NOT NULL -- internal
);

Expand Down
4 changes: 4 additions & 0 deletions staging/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Here we store the ongoing revisions for the files. Directories use numbers,
which point to the revision ID. Anyway, the DB knows where to find its files.


Loading

0 comments on commit 6985bd4

Please sign in to comment.