App-Office-CMS

 view release on metacpan or  search on metacpan

MANIFEST.SKIP  view on Meta::CPAN

\bMakeMaker-\d

# Avoid Module::Build generated and utility files.
\b_build
\bBuild$
\bBuild.bat$

# Avoid Devel::Cover generated files
\bcover_db

# Avoid temp and backup files.
~$
\#$
\.#
\.bak$
\.old$
\.rej$
\.tmp$

# Avoid OS-specific files/dirs
#   Mac OSX metadata

docs/html/cms.help.html  view on Meta::CPAN

<tr><td align="center"><a href="#Duplication_of_Data">Duplication of Data</a></td></tr>
<tr><td align="center"><a href="#1%3A_Create_a_new_Site_and_a_new_Design">1: Create a new Site and a new Design</a></td></tr>
<tr><td align="center"><a href="#2%3A_Build_the_Site_via_it%27s_menu">2: Build the Site via it&#39;s menu</a></td></tr>
<tr><td align="center"><a href="#3%3A_Edit_the_Design%27s_content">3: Edit the Design&#39;s content</a></td></tr>
<tr><td align="center"><a href="#4%3A_Generate_the_web_site%27s_pages">4: Generate the web site&#39;s pages</a></td></tr>
<tr><td align="center"><a href="#Changing_the_names_of_Sites%2FDesigns%2FPages">Changing the names of Sites/Designs/Pages</a></td></tr>
<tr><td align="center"><a href="#1%3A_Editing_names">1: Editing names</a></td></tr>
<tr><td align="center"><a href="#2%3A_Editing_menus">2: Editing menus</a></td></tr>
<tr><td align="center"><a href="#Deleting_Pages">Deleting Pages</a></td></tr>
<tr><td align="center"><a href="#How_do_I_skin_the_Design%3F">How do I skin the Design?</a></td></tr>
<tr><td align="center"><a href="#How_do_I_backup_my_Designs%3F">How do I backup my Designs?</a></td></tr>
</table>
<h1><a class='u' href='#___top' title='click to go to top of document'
name="How_do_I_use_this_CMS?"
>How do I use this CMS?</a></h1>

<p>CMS means Content Management System.</p>

<p>If you&#39;re starting with an empty database,
the program will default to the [New Site] tab.</p>

docs/html/cms.help.html  view on Meta::CPAN

name="How_do_I_skin_the_Design?"
>How do I skin the Design?</a></h1>

<p>See <a href="http://developer.yahoo.com/yui/articles/skinning/" class="podlinkurl"
>http://developer.yahoo.com/yui/articles/skinning/</a>.</p>

<p>YUI is the Yahoo User Interface,
the Javascript library I used to write the client-side code for this program.</p>

<h1><a class='u' href='#___top' title='click to go to top of document'
name="How_do_I_backup_my_Designs?"
>How do I backup my Designs?</a></h1>

<p>All designs are stored in a database,
so it&#39;s a matter of running the database&#39;s standard backup procedure.</p>

<p>That means also that to restore after a mistake,
you need to run the database&#39;s recovery program.</p>

<p>Which is a way of saying that this program does not yet have an undo command.</p>

<!-- end doc -->

</body></html>

docs/pod/cms.help.pod  view on Meta::CPAN


The 'first page' is the one on the Edit Pages tab which appears at the top of the site map.

=head1 How do I skin the Design?

See L<http://developer.yahoo.com/yui/articles/skinning/>.

YUI is the Yahoo User Interface, the Javascript library I used to write the client-side
code for this program.

=head1 How do I backup my Designs?

All designs are stored in a database, so it's a matter of running the database's standard
backup procedure.

That means also that to restore after a mistake, you need to run the database's
recovery program.

Which is a way of saying that this program does not yet have an undo command.

htdocs/assets/templates/app/office/cms/content.js  view on Meta::CPAN

	var action = document.update_content_form.action.value;
	var url    = "<: $form_action :>/content/";

	switch (action)
	{
	case "1":
		url = url + "update";
		break;

	case "2":
		url = url + "backup";
		break;

	case "3":
		url = url + "generate";
		break;
	}

	var p = YAHOO.util.Connect.setForm("update_content_form");

	if (action == 1)

htdocs/assets/templates/app/office/cms/content.tx  view on Meta::CPAN

<td colspan="2"><textarea name="body_text" id="body_text" rows="12" cols="100"><: $body_text :></textarea></td>
</tr>
<tr>
<td></td>
<td><input type="reset" value="Reset" /></td>
<td align="center"><input type="submit" name="submit_<: $context :>_content" id="submit_<: $context :>_content" value="<: $submit_text :>" onClick="document.<: $context :>_content_form.action.value=1" /></td>
</tr>
<tr><td colspan="3"><hr /></td></tr>
<tr>
<td></td>
: if $backup {
<td><input type="submit" name="submit_backup_content" id="submit_backup_content" value="Backup" onClick="document.<: $context :>_content_form.action.value=2" /></td>
: }
: else {
: }
<td align="center" colspan="$colspan"><input type="submit" name="submit_generate_content" id="submit_generate_content" value="Generate" onClick="document.<: $context :>_content_form.action.value=3" /></td>
</tr>
</table>

<input type="hidden" name="action" id="action" value="0" />
<input type="hidden" name="sid" id="sid" value="<: $sid :>" />
</form>

lib/App/Office/CMS.pm  view on Meta::CPAN

=item o Does the database server have pre-requisites?

The code is DBI-based, of course.

Also, the code assumes the database server supports $dbh -> last_insert_id(undef, undef, $table_name, undef).

=item o How do I back up the database?

See the config file .htoffice.cms.conf:

	backup_command = pg_dump -U cms cms
	backup_file = /tmp/pg.cms.backup.dat

When backup_command has a value, the Edit Contents tab gets a [Backup] button, and when this button
is clicked:

=over 4

=item o The command is run

=item o STDOUT and STDERR are captured

=item o If STDERR contains anything, the program exits

=item o Otherwise, STDOUT is written to the output file

=back

So, why are there 2 lines, and not something like 'pg_dump -U cms cms > /tmp/pg.cms.backup.dat'?

Because I use L<Capture::Tiny>, which does not want you to use redirection.

Lastly, the output is written using L<File::Slurper>.

=item o What's this thing called 'context' in the menus and pages tables?

It's the value ("$site_id/$design_id") which ties those 2 tables together, just like a foreign key.

=item o What are these fields menu_orientation_id and os_type_id in the designs table?

lib/App/Office/CMS.pm  view on Meta::CPAN


For massive wikiness (as distinct from wickedness :-) I draw your attention to
both L<Silki> and L<http://foswiki.org/Home/WebHome>.

=back

=head1 TODO

=over 4

=item o Adopt Git::Repository for versioned backup

=item o Clean up error handling

For example, when build_error_result is called, rather than build_success_result, the
data sent to Javascript must be handled slightly differently.

This includes HandleError in DBI's connect() attributes.

=item o Make asset handling more sophisticated

lib/App/Office/CMS.pm  view on Meta::CPAN

=item o Enhance New Site tab with an Edit Site button

This saves the user the effort of going to the Search tab to find a site or design

=item o When clicking on the site map, the Edit Pages fields are updated, but the Edit Content fields are not

=item o Add an option, perhaps, to escape entities when inputting HTML

=item o Adopt DBIx::Connector

=item o Implement user-initiated backup and restore

=item o Change class hierarchy

This is so View does not have to pass so many parameters to its 'has-a' attributes

=item o Adopt L<CGI::Untaint::html> or L<HTML::Defang>

Considered and rejected: L<HTML::Sanitizer>, L<HTML::Scrubber>.

=item o Test CGI::Untaint as to its handling of <script>...</script>

lib/App/Office/CMS/.htoffice.cms.conf  view on Meta::CPAN


host = localhost

[localhost]

# Backup stuff
# ------------
# o Database stuff (below) also refers to database stuff.
# o Session stuff (below) also refers to database stuff.

backup_command = pg_dump -U cms cms
backup_file = /tmp/pg.cms.backup.dat

# CSS stuff
# ---------
# This is a URL.
# My DocumentRoot:    /dev/shm/html.
# hence my disk path: /dev/shm/html/assets/css/app/office/cms.

css_url = /assets/css/app/office/cms

# Database stuff

lib/App/Office/CMS/Controller/Content.pm  view on Meta::CPAN

use String::Dirify;

use Try::Tiny;

# We don't use Moo because we isa CGI::Application.

our $VERSION = '0.93';

# -----------------------------------------------

sub backup
{
	my($self) = @_;

	$self -> log(debug => 'backup()');

	my($target_div) = 'update_content_message_div';

	my($result);

	try
	{
		my($message, $page, $content) = $self -> process_content_form('update');

		if (! $message)
		{
			# Success.

			$message = $self -> param('db') -> content -> backup($page, $content);
			$result  = $self -> build_success_result($page, $message, $target_div);
		}
	}
	catch
	{
		$result = $self -> build_error_result($_, $target_div);
	};

	# update_content_message_div is on screen (under the Edit Content tab)
	# because we're displaying content.

	return JSON::XS -> new -> utf8 -> encode({results => $result});

} # End of backup.

# -----------------------------------------------

sub build_content_hash
{
	my($self, $valid) = @_;

	$self -> log(debug => 'build_content_hash()');

	my($content) =

lib/App/Office/CMS/Controller/Content.pm  view on Meta::CPAN

	};

} # End of build_success_result.

# -----------------------------------------------

sub cgiapp_init
{
	my($self) = @_;

	$self -> run_modes([qw/backup generate update/]);

} # End of cgiapp_init.

# -----------------------------------------------

sub display
{
	my($self) = @_;

	$self -> log(debug => 'display()');

lib/App/Office/CMS/Database/Content.pm  view on Meta::CPAN

	$self -> log(debug => '-' x 50);

	$self -> save_content_record('add', $page, $content);

	return "Saved (add) content for page '$$page{name}'";

} # End of add.

# --------------------------------------------------

sub backup
{
	my($self, $page, $content) = @_;
	my($backup_command) = ${$self -> db -> config}{backup_command};
	my($backup_file)    = ${$self -> db -> config}{backup_file};
	my($stdout)         = $self -> capture_or_die($backup_command);

	write_text($backup_file, $stdout) || die "Error: Can't write backup file: $!\n";

	return $self -> update($page, $content) . " and backed-up";

} # End of backup.

# -----------------------------------------------

sub capture_or_die
{
	my($self, @command)  = @_;
	my($stdout, $stderr) = capture{system(@command)};

	$stderr && die "Error: $stderr\n";

lib/App/Office/CMS/View/Content.pm  view on Meta::CPAN

} # End of build_head_js.

# -----------------------------------------------

sub build_update_content_html
{
	my($self, $site, $design, $page, $asset) = @_;

	$self -> log(debug => 'build_update_content_html()');

	my($backup_command) = ${$self -> config}{backup_command};
	my($content)        = $self -> db -> content -> get_content_by_page_id($$page{id});
	my($context)        = 'update';
	my($param)          =
	{
	 backup      => $backup_command ? 1 : 0, # We only need a Boolean in the template.
	 body_text   => mark_raw($$content{body_text}),
	 colspan     => $backup_command ? 1 : 2, # Make generate button's position look pretty.
	 context     => $context,
	 design_name => $$design{name},
	 head_text   => mark_raw($$content{head_text}),
	 page_name   => $$page{name},
	 sid         => $self -> session -> id,
	 site_name   => $$site{name},
	 submit_text => 'Save',
	};

	return $self -> templater -> render('content.tx', $param);



( run in 0.716 second using v1.01-cache-2.11-cpan-49f99fa48dc )