First pass at adding key files

This commit is contained in:
dsainty
2024-06-17 21:49:12 +10:00
commit aa25e9347f
1274 changed files with 392549 additions and 0 deletions

View File

@ -0,0 +1,394 @@
# ==================================================================
# Plugins::Auth_Facebook - Auto Generated Program Module
#
# Plugins::Auth_Facebook
# Author : Gossamer Threads Inc. (Virginia Lo)
# Version : 1.1
# Updated : Wed Feb 2 10:34:55 2011
#
# ==================================================================
#
package Plugins::Auth_Facebook;
# ==================================================================
use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/:objects/;
use vars qw/$TAINTED $GRAPHURL $CALLBACK $AUTHURL $FBMAPPING/;
use GT::WWW;
use GT::JSON;
use Data::Dumper;
use Links::Plugins;
use open qw(:std :utf8);
use LWP::Simple;
use JSON;
use URI;
use utf8;
# Inherit from base class for debug and error methods
@Plugins::Auth_Facebook::ISA = qw(GT::Base);
# Your code begins here.
{
local $^W = 0;
$TAINTED = substr("$0$^X", 0, 0);
}
$GRAPHURL = "https://graph.facebook.com";
$AUTHURL = $GRAPHURL . '/oauth/access_token';
$FBMAPPING = {
first_name => 'prof_first_name',
last_name => 'prof_last_name',
email => 'comm_email',
};
# PLUGIN HOOKS
# ===================================================================
sub user_auth {
# -------------------------------------------------------------------
# ether facebook postback or user call it.
#
my $cfg = Links::Plugins::get_plugin_user_cfg('Auth_Facebook');
$CALLBACK = $cfg->{fb_postback_url};
my $redirect = $IN->param('url');
my $ajax = $IN->param('ajax');
my $cuser = $USER;
# Check to see if we have the facebook cookie already.
$Links::fbcookie ||= get_facebook_cookie();
my $code = $IN->param('code');
my $connect = $IN->param('connect');
if ($code) {
# ---------------------------------------------------------------------
# User has granted permission to the app to access their information.
# Post a request to facebook to verify the code which can be exchanged for an oauth access token
# ---------------------------------------------------------------------
# If the user authorizes your application, we redirect the user back
# to the redirect URI you specified with a verification string in the
# argument code, which can be exchanged for an oauth access token.
# ---------------------------------------------------------------------
if ($connect) {
$CALLBACK .= "&connect=1";
}
my $linkid = $IN->param('linkid');
if ($linkid) {
$CALLBACK .= "$linkid/";
}
my $authurl = $AUTHURL . "?client_id=" . $cfg->{fb_appid} . "&redirect_uri=" . GT::CGI::escape($CALLBACK) . "&client_secret=" . $cfg->{fb_secret_key} . "&code=" . $code;
my $res = GT::WWW->post($authurl);
#print $IN->header;
#print "<pre>". Dumper($res)."</pre>";
if ($res->{content} =~ /access_token=(.+)$/) {
# we got the access token
my $access_token = $1;
$access_token =~ s/\&.+$//g; # Fix it by removing the &epxire=[timestamp]
#print $access_token . "**";
my $id = $linkid;
use Plugins::SocialMedia;
my $result = Plugins::SocialMedia::post_facebook($access_token, $id);
#my $result = {}; #Plugins::SocialMedia::post_facebook($access_token, $id);
#print "<pre>". Dumper($id,$result)."</pre>";
if ($result) {
if ($result->{id}) {
$DB->table('Links')->update({ facebook_published => $result->{id} }, { ID => $linkid });
}
elsif ($result->{error}) {
$DB->table('Links')->update({ facebook_published_message => $result->{error}->{message} }, { ID => $linkid });
}
$IN->param('t','dev'); #FIXME
require Plugins::SocialMedia;
my $link = Plugins::SocialMedia::format_link($linkid);
print $IN->header;
print Links::user_page('add_success_publish.html', { success => '1', built => 1, %$link });
return;
}
else {
$IN->param('t','dev'); #FIXME
require Plugins::SocialMedia;
my $link = Plugins::SocialMedia::format_link($id);
print $IN->header;
print Links::user_page('add_success_publish.html', { success => '1', built => 1, %$link });
return;
}
=tag
# get the user information
my $userinfo = request_facebook_api('me','email', $access_token);
# check to seee if the user already in community
my $user = user_by_facebook_id($userinfo->{id});
# ---------------------------------------------------------------------
# Now then login user with their facebook account
# ---------------------------------------------------------------------
if ($user) {
my $cookies = [];
my $remember = 1;
my $username = $user->{comm_username};
# create community session.
$user->{session} = comm_create_session(
comm_id => $user->{comm_id},
remember => $remember,
ip => $ENV{REMOTE_ADDR}
);
# Get session cookies, and send user to home page or to redirection.
my $session_cookies = Links::session_cookies($user, $remember ? $CFG->{session_remember_expiry} : undef);
push @$cookies, @$session_cookies;
if ($redirect) {
comm_debug("user |$username| logged in. Redirecting to |$redirect|") if ($CFG->{debug});
print $IN->header( -url => $redirect, -cookie => $cookies );
return;
}
else {
$user->{redirect} = $IN->cookie('fb_redirect');
comm_debug("user |$username| logged in.") if ($CFG->{debug});
$user->{session_cookie_name_user} = $user->{comm_username};
$user->{action} = 'login';
print $IN->header( -cookie => $cookies );
Links::user_page('user_logged_in.html', { %$user });
return;
}
}
else {
# ---------------------------------------------------------------------
# Show signup form if they are not in Community but already authorize our app to access their account
# ---------------------------------------------------------------------
# Write the facebook cookies here so that we can access them again after the user
# provides us with username. I don't see where else this is being done.
# ---------------------------------------------------------------------
my $cookies = [];
my $remember = 1;
my $facebook_cookies = facebook_cookies($userinfo, $remember ? $CFG->{session_remember_expiry} : undef);
push @$cookies, @$facebook_cookies;
if ($connect) {
if (defined $IN->cookie('fb_uid')) {
$userinfo->{facebook_userid} = $IN->cookie('fb_uid');
}
print $IN->header( -cookie => $cookies );
Links::user_page('user_connect.html', { fb_user => $userinfo, user => $cuser });
return;
}
print $IN->header( -cookie => $cookies );
my @questions;
foreach my $question (@{$CFG->{signup_questions}}) {
push @questions, { question => $question };
}
my $res = {
comm_question_loop => \@questions, fb_user => $userinfo, fb_signup => 1,
};
$res->{fancybox} = $IN->param('fancybox') ? 1 : 0;
$res->{iframe} = 1;
$res->{debuginfo} = { cookies => \@$cookies, %$userinfo };
foreach (keys %$userinfo) {
$res->{querystr} .= "&" if ($res->{querystr});
$res->{querystr} .= $_ . "=" . $userinfo->{$_};
}
if ($userinfo->{birthday}) {
($res->{prof_mon}, $res->{prof_day}, $res->{prof_year}) = split ('/', $userinfo->{birthday});
$res->{prof_month} =~ s/^0//g;
$res->{prof_day} =~ s/^0//g;
}
Links::user_page('user_signup_fb_popup.html', $res);
return;
}
=cut
}
else {
print $IN->header;
}
}
elsif ($IN->param('error')) {
print $IN->header;
Links::user_page('user_signup_fb_error.html', { error => $IN->param('error') });
return;
}
else {
# redirect user to facebook and ask for email, offline access, read access
# display=popup mean it's a popup format.
my $cookie = [
$IN->cookie(
-name => "fb_redirect",
-value => $redirect ? $redirect : '',
-expires => undef,
-path => $CFG->{session_cookie_path}
)
];
if ($IN->param('connect')) {
$CALLBACK .= "&connect=1";
}
my $linkid = $IN->param('linkid');
if ($linkid) {
$CALLBACK .= "$linkid/";
my $tags = $IN->param('twitter_hash_tags');
my $newtags;
if ($tags) {
$tags =~ s/\s+//g;
my @tags = split(',',$tags);
for (@tags) {
$newtags .= ' #' . $_;
}
}
$DB->table('Links')->update({ facebook_hashtags => $newtags }, { ID => $linkid }) if ($newtags);
}
my $redirurl = 'https://graph.facebook.com/oauth/authorize?client_id=' . $cfg->{fb_appid} . '&redirect_uri=' . GT::CGI::escape($CALLBACK) . '&scope=email,read_stream,publish_stream,manage_pages';
if (1) { # HAS to have display=popup to show "Log in to Facebook" button
$redirurl .= "&display=popup";
}
print $IN->header( -url => $redirurl, -cookie => $cookie );
return;
}
}
sub request_facebook_api {
# -------------------------------------------------------------------
# generate facebook api and make a request
# the request results are in json format
#
my ($uid, $type, $token, $publish, $args) = @_;
if (!$token) {
$Links::fbcookie ||= get_facebook_cookie();
}
$type ||= "feed";
require GT::WWW;
my $content;
my $www = new GT::WWW;
# Note: apparently we need to unescape the token, not escape it.
# perhaps it's a difference between $token and access_token?
# http://drupal.org/node/905164 post #7 as of 9/29/2010
my $host = $GRAPHURL;
$host =~ s/^(https)?:\/\///g;
$www->protocol($1);
$www->host($host);
if ($publish) {
$www->path("/$uid/feed");
$www->parameters(access_token => GT::CGI::unescape($token || $Links::fbcookie->{access_token}));
$args ||= $IN->get_hash();
#use Data::Dumper; print Dumper($args);
for (qw/message picture name caption description link/) {
$www->parameters($_ => GT::CGI::html_escape($args->{$_}), 1) if ($args->{$_} !~ /^\s*$/);
}
$content = $www->post();
}
else {
my $requestpath = "/" . $uid;
$requestpath .= "/" . $type if ($uid ne 'me');
$www->path($requestpath);
$www->parameters(access_token => GT::CGI::unescape($token || $Links::fbcookie->{access_token}));
$args ||= $IN->get_hash();
if ($uid ne 'me') {
for (keys %$args) {
next if ($_ eq 'arg');
$www->parameters($_ => GT::CGI::html_escape($args->{$_}), 1) if ($args->{$_} !~ /^\s*$/);
}
}
$content = $www->get();
}
return unless ($content);
my $data = eval { $content };
return unless ($data and $data->{content});
my $res = from_json($data->{content});
return $res;
}
sub get_facebook_cookie {
# -------------------------------------------------------------------
# return facebook cookie in hash if exists
#
my $cfg = Links::Plugins::get_plugin_user_cfg('Auth_Facebook');
my ($app_id, $application_secret) = ($cfg->{fb_appid}, $cfg->{fb_secret_key});
my $cookiename = 'fbs_' . $cfg->{fb_appid};
my $cookies = {};
if (defined $ENV{HTTP_COOKIE}) {
for (split /;\s*/, $ENV{HTTP_COOKIE}) {
/(.*)="?(.*)"?/ or next;
my ($key, $val) = (GT::CGI::unescape($1 . $TAINTED), GT::CGI::unescape($2 . $TAINTED));
if ($_ =~ /(.*)="([^"]+)+"/) {
($key, $val) = (GT::CGI::unescape($1 . $TAINTED), GT::CGI::unescape($2 . $TAINTED));
}
$val = [split '&', $val];
foreach (@$val) {
my ($k, $v) = split /=/, $_;
$cookies->{$key}->{$k} = $v;
}
}
}
my $args = $cookies->{$cookiename};
my $payload;
foreach my $key (sort keys %$args) {
if ($key ne 'sig') {
$payload .= $key . '=' . $args->{$key};
}
}
require GT::MD5;
my $md5 = GT::MD5::md5_hex($payload . $application_secret);
return unless ($md5 eq $args->{'sig'});
return $args;
}
sub facebook_cookies {
# -------------------------------------------------------------------
# return facebook cookies, and put it into the cookies list
# in case we need it later.
#
my ($facebookinfo, $expiry) = @_;
$facebookinfo || return;
my $cookies = [
$IN->cookie(
-name => "fb_uid",
-value => $facebookinfo ? $facebookinfo->{id} : '',
-expires => $expiry,
-path => $CFG->{session_cookie_path}
)
];
if ($CFG->{session_cookie_domain}) {
push @$cookies,
$IN->cookie(
-name => "fb_uid",
-value => $facebookinfo ? $facebookinfo->{id} : '',
-expires => $expiry,
-path => $CFG->{session_cookie_path},
-domain => $CFG->{session_cookie_domain}
);
}
return $cookies;
}
sub user_by_facebook_id {
# -------------------------------------------------------------------
# pass in facebook profile id and return the community user
# associated with it if exists.
#
my $uid = shift || return;
my $db = $DB->table('Users');
return;
my $sth = $db->select( { facebook_userid => $uid });
if ($sth->rows) {
my $user = $sth->fetchrow_hashref;
return $user;
}
return;
}
# Always end with a 1.
1;

View File

@ -0,0 +1,368 @@
# ==================================================================
# Plugins::ConvertVideo - Auto Generated Program Module
#
# Plugins::ConvertVideo
# Author : Virginia Lo
# Version : 1.1
# Updated : Wed Feb 21 16:05:27 2007
#
# ==================================================================
#
package Plugins::ConvertVideo;
# ==================================================================
use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/$CFG $IN $DB/;
use Links::Plugins;
use vars qw/$WIDTH $HEIGHT $LINKID $CONVERTBOX $CHECKCONVERTBOX/;
# Inherit from base class for debug and error methods
@Plugins::ConvertVideo::ISA = qw(GT::Base);
# Your code begins here! Good Luck!
# PLUGIN HOOKS
# ===================================================================
sub validate_link_pre {
# -------------------------------------------------------------------
# This subroutine will get called whenever the hook 'validate_link'
# is run. You should call GT::Plugins->action (STOP) if you don't
# want the regular code to run, otherwise the code will continue as
# normal.
#
my ($link) = @_;
$link = convert_video($link);
return $link;
}
sub pre_form_link {
# -------------------------------------------------------------------
#
my $opts = shift;
if ($opts->{mode} =~ /([add|modify])_form/) {
$CONVERTBOX = 1;
if ($1 eq 'add') {
$CHECKCONVERTBOX = 1;
}
}
return $opts;
}
sub post_form_link {
# -------------------------------------------------------------------
#
my @args = @_;
if (($CONVERTBOX and $IN->param('db') eq 'Links')
|| $IN->param('action') eq 'link_add_form'
|| $IN->param('action') eq 'link_modify_form')
{
my $checked = '';
if ($IN->param('action') eq 'link_add_form' || $CHECKCONVERTBOX) {
$checked = ' checked';
}
my $font = 'face="Tahoma,Arial,Helvetica" size="2"';
$args[0] .=
qq~<p><table border=1 cellpadding=0 bgcolor="#FFFFFF" cellspacing=0 width="500"><tr><td>
<table border=0 bgcolor="#FFFFFF" width="500"><tr>
<td width="20%" valign="top"><font $font>Converting Video(s)?</td>
<td width="80%"><font $font><input type="checkbox" name="admin_convert_video" value="1"$checked/> YES </td>
</tr></table>
</td></tr></table>~;
}
return @args;
}
sub modify_link_pre {
# -------------------------------------------------------------------
# This subroutine will get called whenever the hook 'modify_link'
# is run. You should call GT::Plugins->action (STOP) if you don't
# want the regular code to run, otherwise the code will continue as
# normal.
#
my @args = @_;
my $link = $args[0];
$LINKID = $link->{ID};
return @args;
}
sub modify_link_post {
# -------------------------------------------------------------------
#
my $ret = shift;
if ($ret and $LINKID and $IN->param('admin_convert_video')) {
my $linkdb = $DB->table('Links');
my $link = convert_video($linkdb->get($LINKID));
my $res = $linkdb->update($link, { ID => $LINKID });
if (!$res) {
die "Can't modify link #$LINKID: $GT::SQL::error\n";
}
}
return $ret;
}
sub add_link_post {
# -------------------------------------------------------------------
#
$LINKID = shift;
if ($LINKID) {
&modify_link_post(1);
}
return $LINKID;
}
sub convert_video {
# ------------------------------------------------------------------
# Grab video details
my ($link) = @_;
my $linkid = $link->{ID};
my $result = { ID => $linkid };
my $linksdb = $DB->table('Links');
my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo');
my $vf_field = $cfg->{video_file_field};
my $ff_field = $cfg->{flash_file_field};
my $thumb = $cfg->{thumbnail_file_field};
my $image = $cfg->{image_file_field};
my $url_field = $cfg->{video_url_field};
if ($cfg->{flash_dimension} =~ /\s*(\d+)x(\d+)\s*/) {
($WIDTH, $HEIGHT) = ($1, $2);
}
my $url = $link->{$url_field};
if ($url and $url ne '' and $url ne 'http://') {
my $fh = $linksdb->file_info($image, $linkid) or return $result;
require Plugins::SlideShow;
# save the Image file (if required)
my $fname = Plugins::SlideShow::get_filename("$fh");
my $efname = GT::CGI::escape($fname);
my $main_fpath = $CFG->{admin_root_path} . "/tmp/work-$efname";
if ($main_fpath ne "$fh") {
open IMG, ">$main_fpath" or return throw_error( $! );
binmode IMG;
print IMG <$fh>;
close IMG;
}
my $quality = 75;
my $image_path = $CFG->{admin_root_path} . "/tmp/image-$efname";
Plugins::SlideShow::resize_image($main_fpath, $image_path, $WIDTH, $HEIGHT, $quality);
$result->{$image} = GT::SQL::File->open($image_path);
if ($cfg->{thumbnail_size} =~ /\s*(\d+)x(\d+)\s*/) {
my ($thumb_width, $thumb_height) = ($1, $2);
my $thumb_path = $CFG->{admin_root_path} . "/tmp/thumbnail-$efname";
Plugins::SlideShow::resize_image($main_fpath, $thumb_path, $thumb_width, $thumb_height, $quality);
$result->{$thumb} = GT::SQL::File->open($thumb_path);
}
return $result;
}
my $fh = $linksdb->file_info($vf_field, $linkid) or return $result;
my $full_path = "$fh";
my $video = {};
my $filename = $full_path;
$filename =~ s/(.+)\/\d-([^\/]+)\.$/$2/g;
my $flv_file_path =
$CFG->{admin_root_path} . "/tmp/" . $linkid . ".flv";
my $thumb_path =
$CFG->{admin_root_path} . "/tmp/" . "thumbnail-" . $linkid . ".png";
my $image_path =
$CFG->{admin_root_path} . "/tmp/" . "image-" . $linkid . ".png";
my $buf = `ffmpeg -i "$full_path" 2>&1`;
if ($buf =~ /Video:\s.+\s+(\d+)x(\d+),?.*\s+(\d+)\s+(?:fps|tb)/) {
$video->{width} = $1;
$video->{height} = $2;
$video->{fps} = $3;
if ($buf =~ /Duration:\s+(\d+):(\d+):(\d+).+bitrate:\s+(\d+)\s+kb\/s/)
{
$video->{duration} = $1 * 3600 + $2 * 60 + $3;
$video->{bitrate} = $4;
}
} else {
warn "Couldn't get video info";
return $result;
}
# Figure out any scaling we might need to do
if ($video->{width} > $WIDTH and $video->{height} > $HEIGHT) {
# Choose the larger dimension to scale down
if ($video->{width} / $WIDTH > $video->{height} / $HEIGHT) {
$video->{out_height} =
int($video->{height} * $WIDTH / $video->{width});
$video->{out_width} = $WIDTH;
} else {
$video->{out_width} =
int($video->{width} * $HEIGHT / $video->{height});
$video->{out_height} = $HEIGHT;
}
} elsif ($video->{width} > $WIDTH) {
$video->{out_height} = int($HEIGHT * $WIDTH / $video->{width});
$video->{out_width} = $WIDTH;
} elsif ($video->{height} > $HEIGHT) {
$video->{out_height} = $HEIGHT;
$video->{out_width} = int($video->{height} * $WIDTH / $HEIGHT);
}
# Source dimensions are smaller than output
else {
$video->{out_height} = $video->{height};
$video->{out_width} = $video->{width};
}
$video->{out_height}++ if $video->{out_height} % 2;
$video->{out_width}++ if $video->{out_width} % 2;
$video->{out_padtop} = int(($HEIGHT - $video->{out_height}) / 2);
$video->{out_padtop}-- if $video->{out_padtop} % 2;
$video->{out_padbottom} =
$HEIGHT - $video->{out_height} - $video->{out_padtop};
$video->{out_padleft} = int(($WIDTH - $video->{out_width}) / 2);
$video->{out_padleft}-- if $video->{out_padleft} % 2;
$video->{out_padright} =
$WIDTH - $video->{out_width} - $video->{out_padleft};
# Encode the video
system(
"ffmpeg",
'-i', "$full_path",
'-y', # overwrite
# video options
'-vf', "scale=$video->{out_width}:$video->{out_height},pad='$WIDTH:$HEIGHT:$video->{out_padleft}:$video->{out_padtop}'",
# audio options
'-ar', 22050, # audio sampling rate (Hz)
'-ab', 64, # audio bitrate (kb/s)
'-ac', 2, # audio channels
# encoding options
# '-b', 100000, # video bitrate (b/s)
'-qscale',
$cfg->{flash_quality} || 6, # quality scale (1 [best] - 31 [worst])
# watermark
# '-vhook', '/usr/lib/vhook/watermark.so -f admin/water3.gif',
# output
"$flv_file_path",
);
=tag
# video options
'-r', $video->{fps}, # frame rate
'-s', "$video->{out_width2}x$video->{out_height2}", # frame size
'-padtop', $video->{out_padtop},
'-padbottom', $video->{out_padbottom},
'-padleft', $video->{out_padleft},
'-padright', $video->{out_padright},
=cut
# -----------------------------------------------------------------------------------------
# -----------------------------------------------------------------------------------------
# Generate a thumbnail (a quarter of the way through)
my $when = int($video->{duration} * 0.25);
my $hours = int($when / 3600);
my $mins = int($when / 60) - $hours * 60;
my $secs = $when - $hours * 3600 - $mins * 60;
$when = sprintf("%.2d:%.2d:%.2d", $hours, $mins, $secs);
if ($cfg->{thumbnail_size} and $cfg->{thumbnail_file_field}) {
system(
"ffmpeg",
'-i', "$flv_file_path",
'-y', # overwrite
'-vframes', 1, # record 1 frame
'-ss', $when,
'-an', # no audio
'-vcodec', 'png',
'-f', 'rawvideo',
'-s', $cfg->{thumbnail_size},
"$thumb_path",
);
}
system(
"ffmpeg",
'-i', "$flv_file_path",
'-y', # overwrite
'-vframes', 1, # record 1 frame
'-ss', $when,
'-an', # no audio
'-vcodec', 'png',
'-f', 'rawvideo',
'-s', "${WIDTH}x$HEIGHT", # frame size
"$image_path",
);
$result->{$ff_field} = GT::SQL::File->open($flv_file_path);
$result->{$image} = GT::SQL::File->open($image_path);
$result->{$thumb} = GT::SQL::File->open($thumb_path)
if ($cfg->{thumbnail_file_field} and $thumb_path);
return $result;
}
sub get_file_path {
# ---------------------------------------------------------------------------
# return file path of a file column
#
my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo');
my $id = shift;
my $field_name = shift || "flash_file_field";
my $field = $cfg->{$field_name};
my $wantpath = shift || 0;
my $fh = $DB->table('Links')->file_info($field, $id);
return { $field_name . "_path" => '' } if (!$fh);
my $fdir = $fh->File_Directory();
my $full_path = "$fh";
my $rel_path = $full_path;
$rel_path =~ s,$fdir,,;
$rel_path =~ s,%,%25,g;
if ($wantpath) {
return $rel_path;
}
return { $field_name . "_path" => $cfg->{video_url} . $rel_path };
}
sub get_flash_dimension {
my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo');
my $width = 320;
my $height = 240;
if ($cfg->{flash_dimension} =~ /\s*(\d+)x(\d+)\s*/) {
($width, $height) = ($1, $2);
}
return { 'video_width' => $width, 'video_height' => $height };
}
sub get_video_max_size {
my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo');
my $field_name = $cfg->{video_file_field};
my %cols = $DB->table('Links')->_file_cols();
return $cols{$field_name}->{file_max_size};
}
# Always end with a 1.
1;

View File

@ -0,0 +1,336 @@
# ==================================================================
# Plugins::ConvertVideo - Auto Generated Program Module
#
# Plugins::ConvertVideo
# Author : Virginia Lo
# Version : 1.1
# Updated : Wed Feb 21 16:05:27 2007
#
# ==================================================================
#
package Plugins::ConvertVideo;
# ==================================================================
use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/$CFG $IN $DB/;
use Links::Plugins;
use vars qw/$WIDTH $HEIGHT $LINKID $CONVERTBOX $CHECKCONVERTBOX/;
# Inherit from base class for debug and error methods
@Plugins::ConvertVideo::ISA = qw(GT::Base);
# Your code begins here! Good Luck!
# PLUGIN HOOKS
# ===================================================================
sub validate_link_pre {
# -------------------------------------------------------------------
# This subroutine will get called whenever the hook 'validate_link'
# is run. You should call GT::Plugins->action (STOP) if you don't
# want the regular code to run, otherwise the code will continue as
# normal.
#
my ($link) = @_;
$link = convert_video($link);
return $link;
}
sub pre_form_link {
# -------------------------------------------------------------------
#
my $opts = shift;
if ($opts->{mode} =~ /([add|modify])_form/) {
$CONVERTBOX = 1;
if ($1 eq 'add') {
$CHECKCONVERTBOX = 1;
}
}
return $opts;
}
sub post_form_link {
# -------------------------------------------------------------------
#
my @args = @_;
if (($CONVERTBOX and $IN->param('db') eq 'Links')
|| $IN->param('action') eq 'link_add_form'
|| $IN->param('action') eq 'link_modify_form')
{
my $checked = '';
if ($IN->param('action') eq 'link_add_form' || $CHECKCONVERTBOX) {
$checked = ' checked';
}
my $font = 'face="Tahoma,Arial,Helvetica" size="2"';
$args[0] .=
qq~<p><table border=1 cellpadding=0 bgcolor="#FFFFFF" cellspacing=0 width="500"><tr><td>
<table border=0 bgcolor="#FFFFFF" width="500"><tr>
<td width="20%" valign="top"><font $font>Converting Video(s)?</td>
<td width="80%"><font $font><input type="checkbox" name="admin_convert_video" value="1"$checked/> YES </td>
</tr></table>
</td></tr></table>~;
}
return @args;
}
sub modify_link_pre {
# -------------------------------------------------------------------
# This subroutine will get called whenever the hook 'modify_link'
# is run. You should call GT::Plugins->action (STOP) if you don't
# want the regular code to run, otherwise the code will continue as
# normal.
#
my @args = @_;
my $link = $args[0];
$LINKID = $link->{ID};
return @args;
}
sub modify_link_post {
# -------------------------------------------------------------------
#
my $ret = shift;
if ($ret and $LINKID and $IN->param('admin_convert_video')) {
my $linkdb = $DB->table('Links');
my $link = convert_video({ ID => $LINKID });
my $res = $linkdb->update($link, { ID => $LINKID });
if (!$res) {
die "Can't modify link #$LINKID: $GT::SQL::error\n";
}
}
return $ret;
}
sub add_link_post {
# -------------------------------------------------------------------
#
$LINKID = shift;
if ($LINKID) {
&modify_link_post(1);
}
return $LINKID;
}
sub convert_video {
# ------------------------------------------------------------------
# Grab video details
my ($link) = @_;
my $linksdb = $DB->table('Links');
my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo');
my $vf_field = $cfg->{video_file_field};
my $ff_field = $cfg->{flash_file_field};
my $thumb = $cfg->{thumbnail_file_field};
my $image = $cfg->{image_file_field};
my $fh = $linksdb->file_info($vf_field, $link->{ID}) or return $link;
my $full_path = "$fh";
my $video = {};
my $filename = $full_path;
$filename =~ s/(.+)\/\d-([^\/]+)\.$/$2/g;
my $flv_file_path =
$CFG->{admin_root_path} . "/tmp/" . $link->{ID} . ".flv";
my $thumb_path =
$CFG->{admin_root_path} . "/tmp/" . "thumbnail-" . $link->{ID} . ".png";
my $image_path =
$CFG->{admin_root_path} . "/tmp/" . "image-" . $link->{ID} . ".png";
my $buf = `ffmpeg -i "$full_path" 2>&1`;
if ($cfg->{flash_dimension} =~ /\s*(\d+)x(\d+)\s*/) {
($WIDTH, $HEIGHT) = ($1, $2);
}
if ($buf =~ /Video:.+\s+(\d+)x(\d+),?.*\s+(\d+\.\d+)\s+(?:fps|tb)/) {
$video->{width} = $1;
$video->{height} = $2;
$video->{fps} = $3;
if ($buf =~ /Duration:\s+(\d+):(\d+):(\d+).+bitrate:\s+(\d+)\s+kb\/s/)
{
$video->{duration} = $1 * 3600 + $2 * 60 + $3;
$video->{bitrate} = $4;
}
} else {
warn "Couldn't get video info";
return $link;
}
# Figure out any scaling we might need to do
if ($video->{width} > $WIDTH and $video->{height} > $HEIGHT) {
# Choose the larger dimension to scale down
if ($video->{width} / $WIDTH > $video->{height} / $HEIGHT) {
$video->{out_height} =
int($video->{height} * $WIDTH / $video->{width});
$video->{out_width} = $WIDTH;
} else {
$video->{out_width} =
int($video->{width} * $HEIGHT / $video->{height});
$video->{out_height} = $HEIGHT;
}
} elsif ($video->{width} > $WIDTH) {
$video->{out_height} = int($HEIGHT * $WIDTH / $video->{width});
$video->{out_width} = $WIDTH;
} elsif ($video->{height} > $HEIGHT) {
$video->{out_height} = $HEIGHT;
$video->{out_width} = int($video->{height} * $WIDTH / $HEIGHT);
}
# Source dimensions are smaller than output
else {
$video->{out_height} = $video->{height};
$video->{out_width} = $video->{width};
}
$video->{out_height}++ if $video->{out_height} % 2;
$video->{out_width}++ if $video->{out_width} % 2;
$video->{out_padtop} = int(($HEIGHT - $video->{out_height}) / 2);
$video->{out_padtop}-- if $video->{out_padtop} % 2;
$video->{out_padbottom} =
$HEIGHT - $video->{out_height} - $video->{out_padtop};
$video->{out_padleft} = int(($WIDTH - $video->{out_width}) / 2);
$video->{out_padleft}-- if $video->{out_padleft} % 2;
$video->{out_padright} =
$WIDTH - $video->{out_width} - $video->{out_padleft};
# Encode the video
system(
"ffmpeg",
'-i', "$full_path",
'-y', # overwrite
# video options
'-r', $video->{fps}, # frame rate
'-s', "$video->{out_width}x$video->{out_height}", # frame size
'-padtop', $video->{out_padtop},
'-padbottom', $video->{out_padbottom},
'-padleft', $video->{out_padleft},
'-padright', $video->{out_padright},
# audio options
'-ar', 22050, # audio sampling rate (Hz)
'-ab', 64, # audio bitrate (kb/s)
'-ac', 2, # audio channels
# encoding options
# '-b', 100000, # video bitrate (b/s)
'-qscale',
$cfg->{flash_quality} || 6, # quality scale (1 [best] - 31 [worst])
# watermark
# '-vhook', '/usr/lib/vhook/watermark.so -f admin/water3.gif',
# output
"$flv_file_path",
);
=tag
# video options
'-r', $video->{fps}, # frame rate
'-s', "$video->{out_width2}x$video->{out_height2}", # frame size
'-padtop', $video->{out_padtop},
'-padbottom', $video->{out_padbottom},
'-padleft', $video->{out_padleft},
'-padright', $video->{out_padright},
=cut
# -----------------------------------------------------------------------------------------
# -----------------------------------------------------------------------------------------
# Generate a thumbnail (a quarter of the way through)
my $when = int($video->{duration} * 0.25);
my $hours = int($when / 3600);
my $mins = int($when / 60) - $hours * 60;
my $secs = $when - $hours * 3600 - $mins * 60;
$when = sprintf("%.2d:%.2d:%.2d", $hours, $mins, $secs);
if ($cfg->{thumbnail_size} and $cfg->{thumbnail_file_field}) {
system(
"ffmpeg",
'-i', "$flv_file_path",
'-y', # overwrite
'-vframes', 1, # record 1 frame
'-ss', $when,
'-an', # no audio
'-vcodec', 'png',
'-f', 'rawvideo',
'-s', $cfg->{thumbnail_size},
"$thumb_path",
);
}
system(
"ffmpeg",
'-i', "$flv_file_path",
'-y', # overwrite
'-vframes', 1, # record 1 frame
'-ss', $when,
'-an', # no audio
'-vcodec', 'png',
'-f', 'rawvideo',
'-s', "${WIDTH}x$HEIGHT", # frame size
"$image_path",
);
$link->{$ff_field} = GT::SQL::File->open($flv_file_path);
$link->{$image} = GT::SQL::File->open($image_path);
$link->{$thumb} = GT::SQL::File->open($thumb_path)
if ($cfg->{thumbnail_file_field} and $thumb_path);
return $link;
}
sub get_file_path {
# ---------------------------------------------------------------------------
# return file path of a file column
#
my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo');
my $id = shift;
my $field_name = shift || "flash_file_field";
my $field = $cfg->{$field_name};
my $wantpath = shift || 0;
my $fh = $DB->table('Links')->file_info($field, $id);
return { $field_name . "_path" => '' } if (!$fh);
my $fdir = $fh->File_Directory();
my $full_path = "$fh";
my $rel_path = $full_path;
$rel_path =~ s,$fdir,,;
$rel_path =~ s,%,%25,g;
if ($wantpath) {
return $rel_path;
}
return { $field_name . "_path" => $cfg->{video_url} . $rel_path };
}
sub get_flash_dimension {
my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo');
my $width = 320;
my $height = 240;
if ($cfg->{flash_dimension} =~ /\s*(\d+)x(\d+)\s*/) {
($width, $height) = ($1, $2);
}
return { 'video_width' => $width, 'video_height' => $height };
}
sub get_video_max_size {
my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo');
my $field_name = $cfg->{video_file_field};
my %cols = $DB->table('Links')->_file_cols();
return $cols{$field_name}->{file_max_size};
}
# Always end with a 1.
1;

View File

@ -0,0 +1,66 @@
# ==================================================================
# Plugins::HandlePage - Auto Generated Program Module
#
# Plugins::HandlePage
# Author : Gossamer Threads Inc. (Virginia Lo)
# Version : 1.0
# Updated : Tue Jun 7 15:32:59 2011
#
# ==================================================================
#
package Plugins::HandlePage;
# ==================================================================
use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/:objects/;
use Links::SiteHTML;
# Inherit from base class for debug and error methods
@Plugins::HandlePage::ISA = qw(GT::Base);
# Your code begins here.
# PLUGIN HOOKS
# ===================================================================
sub pre_handle_page {
# -----------------------------------------------------------------------------
# This subroutine will be called whenever the hook 'handle_page' is run. You
# should call $PLG->action(STOP) if you don't want the regular
# 'handle_page' code to run, otherwise the code will continue as normal.
#
my (@args) = @_;
# Do something useful here
if (my $page2 = $IN->param('page2')) {
$page2 =~ /.+_(\d+).html/;
my $id = $1;
my $linksdb = $DB->table('Links','CatLinks');
my $link = $linksdb->select( { LinkID => $id })->fetchrow_hashref;
if ($link) {
$link = Links::SiteHTML::tags('link',$link, $link->{CategoryID});
$link->{detailed_url} =~ /$CFG->{build_root_url}\/(.+)$/;
my $match = $1;
if ($page2 ne $match) {
print $IN->redirect( -url => $link->{detailed_url}, -permanent => 1 );
#print $IN->header . $page2 . "<br />";
#print $link->{detailed_url} . " ($page2) should be redirected.";
}
}
else {
print "Status: 404" . $GT::CGI::EOL;
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('PAGE_INVALIDDETAIL',$id) });
}
}
return @args;
}
# Always end with a 1.
1;

View File

@ -0,0 +1,231 @@
# ==================================================================
# Plugins::MostPopular - Auto Generated Program Module
#
# Plugins::MostPopular
# Author : Virginia Lo
# Version : 1.0
# Updated : Tue Sep 4 11:23:30 2007
#
# ==================================================================
#
package Plugins::MostPopular;
# ==================================================================
use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/:objects/;
# Inherit from base class for debug and error methods
@Plugins::MostPopular::ISA = qw(GT::Base);
# Your code begins here.
# PLUGIN HOOKS
# ===================================================================
sub jump_link {
# -----------------------------------------------------------------------------
# This subroutine will be called whenever the hook 'jump_link' is run. You
# should call $PLG->action(STOP) if you don't want the regular
# 'jump_link' code to run, otherwise the code will continue as normal.
#
$PLG->action(STOP);
my $links = $DB->table('Links');
my $id = $IN->param('ID') || $IN->param('Detailed');
my $action = $IN->param('action') || '';
my $goto = '';
my $rec = {};
if ($CFG->{framed_jump} and $id and $action eq 'jump_frame') {
my $error;
if ($id !~ /^\d+$/) {
$error = Links::language('JUMP_INVALIDID', $id);
}
else {
$rec = $links->select({ ID => $id }, VIEWABLE)->fetchrow_hashref;
unless ($rec) {
$error = Links::language('JUMP_INVALIDID', $id);
$rec = {};
}
elsif ($CFG->{build_detailed}) {
$rec->{detailed_url} = "$CFG->{build_detail_url}/" . $links->detailed_url($id);
}
}
print $IN->header();
print Links::SiteHTML::display('jump_frame', { error => $error, %$rec });
return;
}
# If we are chosing a random link, then get the total and go to one at random.
if (lc $id eq "random") {
my $offset = int rand $links->count(VIEWABLE);
$links->select_options("LIMIT 1 OFFSET $offset");
my $sth = $links->select(qw/ID URL/ => VIEWABLE);
($id, $goto) = $sth->fetchrow_array;
}
elsif (defined $id) {
if ($id !~ /^\d+$/) {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('JUMP_INVALIDID', $id) });
return;
}
# Find out if we're going to be displaying a file
my $col = $IN->param('v') || $IN->param('dl') || $IN->param('view') || $IN->param('download');
if ($col) {
# in this case, we need to know from what table we want to load our data from.
# It will by default pull information from the Links table, however if the
# DB=tablename option is used, it will apply the request to that table instead
my $table_name = $IN->param('DB') || 'Links';
unless ($table_name =~ m/^\w+$/) {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('FILE_TABLEFORMAT' ) });
return;
};
if ($table_name ne 'Links') {
eval { $links = $DB->table($table_name) };
if ($@) {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('FILE_TABLE', $table_name, $GT::SQL::error) });
return;
}
}
my $fh;
eval { $fh = $links->file_info($col, $id); };
if ($fh) {
if ($IN->param('v') or $IN->param('view')) { # Viewing
print $IN->header($IN->file_headers(
filename => $fh->File_Name,
mimetype => $fh->File_MimeType,
inline => 1,
size => $fh->File_Size
));
}
else { # Downloading
print $IN->header($IN->file_headers(
filename => $fh->File_Name,
mimetype => $fh->File_MimeType,
inline => 0,
size => $fh->File_Size
));
}
binmode $fh;
while (read($fh, my $buffer, 65536)) {
print $buffer;
}
return 1;
}
else {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('FILE_UNKNOWN', $id) });
return;
}
}
# Jump to a URL, bump the hit counter.
else {
$rec = $links->select({ ID => $id }, VIEWABLE)->fetchrow_hashref;
unless ($rec) {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('JUMP_INVALIDID', $id) });
return;
}
$goto = $rec->{URL};
my $clicktrack = $DB->table('ClickTrack');
my $customdb = $DB->table('ClickTrack_Custom');
my $rows = $clicktrack->count({ LinkID => $id, IP => $ENV{REMOTE_ADDR}, ClickType => 'Hits' });
unless ($rows) {
eval {
$clicktrack->insert({ LinkID => $id, IP => $ENV{REMOTE_ADDR}, ClickType => 'Hits', Created => \"NOW()" });
$customdb->insert({ click_linkid => $id, click_date => \"NOW()" });
$links->update({ Hits => \"Hits + 1", Timestmp => $rec->{Timestmp} }, { ID => $id }, { GT_SQL_SKIP_INDEX => 1 });
};
}
}
}
# Oops, no link.
else {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('JUMP_INVALIDID', $id) });
return;
}
# Redirect to a detailed page if requested.
if ($CFG->{build_detailed} and $IN->param('Detailed')) {
$goto = Links::transform_url("$CFG->{build_detail_url}/" . $links->detailed_url($id));
}
($goto =~ m,^\w+://,) or ($goto = "http://$goto");
unless (defined $goto) {
my $error = ($IN->param('ID') eq 'random') ? Links::language('RANDOM_NOLINKS') : Links::language('JUMP_INVALIDID', $id);
print $IN->header();
print Links::SiteHTML::display('error', { error => $error });
return;
}
if ($goto) {
if ($CFG->{framed_jump} and not ($CFG->{build_detailed} and $IN->param('Detailed'))) {
unless (keys %$rec) {
$rec = $links->select({ ID => $id }, VIEWABLE)->fetchrow_hashref;
}
$rec->{detailed_url} = "$CFG->{build_detail_url}/" . $links->detailed_url($id) if $CFG->{build_detailed};
print $IN->header();
print Links::SiteHTML::display('jump', { destination => $goto, %$rec });
return;
}
else {
print $IN->redirect($goto);
}
}
else {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('JUMP_INVALIDID', $id) });
return;
}
}
sub generate_popular_links {
my $mh = shift || 5;
if ($GLinks::MOSTPOP) {
return $GLinks::MOSTPOP;
}
my $today = GT::Date::date_get();
require Links::Plugins;
my $cfg = Links::Plugins::get_plugin_user_cfg('MostPopular');
my $last_x_days = $cfg->{last_x_days} || 14;
my $from_date = GT::Date::date_sub($today, $last_x_days);
my $to_date = GT::Date::date_sub($today, 0);
require GT::SQL::Condition;
#my $cond = GT::SQL::Condition->new('click_date', '>=', $from_date, 'click_date','<=', $to_date);
my $cond = GT::SQL::Condition->new('Mod_Date', '>=', $from_date, 'Mod_Date','<=', $to_date);
#my $db = $DB->table('ClickTrack_Custom');
my $db = $DB->table('Links');
my $linksdb = $DB->table('Links');
use Data::Dumper;
#$db->select_options('GROUP by click_linkid','ORDER BY count desc',"Limit $mh");
$db->select_options('ORDER BY Hits DESC',"Limit $mh");
#my $sth = $db->select($cond, ['count(*) as count', 'click_linkid']);
my $sth = $db->select($cond, ['ID']);
my @loop;
while (my $row = $sth->fetchrow_hashref()) {
my $link = $linksdb->get($row->{ID});
$link = Links::SiteHTML::tags('link',$link);
push @loop, { %$link, %$row };
}
$GLinks::MOSTPOP = { MostPopularLinks => \@loop, FromDate => $from_date, ToDate => $to_date };
return $GLinks::MOSTPOP;
}
# Always end with a 1.
1;

View File

@ -0,0 +1,47 @@
# ==================================================================
# Plugins::NewestReviews - Auto Generated Program Module
#
# Plugins::NewestReviews
# Author : Jordan Rapp
# Version : 1.0
# Updated : Wed Sep 11 20:07:11 2008
#
# ==================================================================
#
package Plugins::NewestReviews;
# ==================================================================
use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/:objects/;
# Inherit from base class for debug and error methods
@Plugins::NewestReviews::ISA = qw(GT::Base);
# Your code begins here.
# PLUGIN HOOKS
# ===================================================================
sub generate_newest_reviews {
my $mh = shift || 5;
require Links::Plugins;
#my $cfg = Links::Plugins::get_plugin_user_cfg('MostPopular');
my $db = $DB->table('Reviews');
my $linksdb = $DB->table('Links');
use Data::Dumper;
my $sth = $db->do("SELECT Review_Subject, Review_LinkID FROM glinks_Reviews WHERE Review_Validated = 'Yes' ORDER BY Review_Date DESC LIMIT 5");
my @loop;
while (my $row = $sth->fetchrow_hashref()) {
my $link = $linksdb->get($row->{Review_LinkID});
$link = Links::SiteHTML::tags('link',$link);
push @loop, { %$link, %$row };
}
return { NewestReviewsLinks => \@loop };
}
# Always end with a 1.
1;

View File

@ -0,0 +1,153 @@
# ==================================================================
# Plugins::OverrideModDate - Auto Generated Program Module
#
# Plugins::OverrideModDate
# Author : Gossamer Threads Inc.
# Version : 1.0
# Updated : Mon Sep 24 14:34:23 2007
#
# ==================================================================
#
package Plugins::OverrideModDate;
# ==================================================================
use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/:objects/;
use Links::Build;
use Links::SiteHTML;
# Inherit from base class for debug and error methods
@Plugins::OverrideModDate::ISA = qw(GT::Base);
# Your code begins here.
# PLUGIN HOOKS
# ===================================================================
sub post_modify_link {
# -------------------------------------------------------------------
# Modify a single link.
#
my $ret = shift;
return $ret if (!$ret);
my $new = {};
my $update = 0;
Links::init_date();
if ($IN->param('Add_Date') =~ /^\d\d\d\d-\d\d-\d\d$/) {
$new->{Add_Date} = $IN->param('Add_Date');
$update = 1;
}
if ($IN->param('Mod_Date') =~ /^\d\d\d\d-\d\d-\d\d$/) {
$new->{Mod_Date} = $IN->param('Mod_Date');
$update = 1;
}
my $id = $IN->param('ID') || $IN->param('LinkID');
if ($id and $update) {
$DB->table('Links')->update({ %$new }, { ID => $id });
}
return $ret;
}
sub pre_handle {
# ---------------------------------------------------
# Determine what to do.
#
my @args = @_;
my $link_id = $IN->param('LinkID');
if ($CFG->{user_required} and !$USER) {
$PLG->action(STOP);
print $IN->redirect(Links::redirect_login_url('modify'));
return @args;
}
# Perform the link modification
if ($IN->param('modify')) {
return @args;
}
elsif ($USER) {
# Display the link modify form (for a specific link)
if ($IN->param('LinkID')) {
$PLG->action(STOP);
_modify_passed_in();
}
}
return @args;
}
sub _modify_passed_in {
# --------------------------------------------------------
# Display link that was passed in.
#
my $lid = $IN->param('LinkID');
my $link_db = $DB->table('Links');
my $mtl = Links::Build::build('title', Links::language('LINKS_MODIFY'), "$CFG->{db_cgi_url}/modify.cgi?LinkID=$lid");
my $sth = $link_db->select({ ID => $lid, LinkOwner => $USER->{Username} }, VIEWABLE);
if ($USER->{Status} eq 'Administrator') {
$sth = $link_db->select({ ID => $lid }, VIEWABLE);
}
if ($sth->rows) {
my $link = $sth->fetchrow_hashref;
my @ids = $DB->table('CatLinks')->select('CategoryID', { LinkID => $link->{ID} })->fetchall_list;
$IN->param('CatLinks.CategoryID', \@ids);
$link->{Contact_Name} ||= $USER->{Name} || $USER->{Username};
$link->{Contact_Email} ||= $USER->{Email};
my $category = {};
if ($CFG->{db_gen_category_list} < 2) {
require Links::Tools;
$category = Links::Tools::category_list();
$category->{Category} = sub { Links::Tools::category_list_html() };
}
print $IN->header();
print Links::SiteHTML::display('modify', {
main_title_loop => $mtl,
%$link,
%$category
});
}
elsif (!$CFG->{user_required}) {
require Links::User::Modify;
Links::User::Modify::_modify_form();
}
else {
print $IN->header();
print Links::SiteHTML::display('error', { error => Links::language('MODIFY_NOTOWNER'), LinkID => $lid, main_title_loop => $mtl });
}
}
sub post_add_link {
# -------------------------------------------------------------------
# Modify a single link.
#
my $ret = shift;
return $ret if (!$ret);
my $new = {};
my $update = 0;
Links::init_date();
if ($IN->param('Add_Date') =~ /^\d\d\d\d-\d\d-\d\d$/) {
$new->{Add_Date} = $IN->param('Add_Date');
$update = 1;
}
if ($IN->param('Mod_Date') =~ /^\d\d\d\d-\d\d-\d\d$/) {
$new->{Mod_Date} = $IN->param('Mod_Date');
$update = 1;
}
my $id = $ret->{ID};
if ($id and $update) {
$DB->table('Links')->update({ %$new }, { ID => $id });
}
return $ret;
}
# Always end with a 1.
1;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,619 @@
# ==================================================================
# Plugins::SocialMedia - Auto Generated Program Module
#
# Plugins::SocialMedia
# Author : Gossamer Threads Inc.
# Version : 1.0
# Updated : Tue Oct 29 11:32:05 2013
#
# ==================================================================
#
package Plugins::SocialMedia;
# ==================================================================
use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/:objects/;
use Links::Build;
use Links::SiteHTML;
use Net::Twitter;
use Links::Plugins;
use LWP::Simple;
use JSON;
use URI;
use utf8;
use vars qw/$USE_HTML $TIME_START $TOTAL_TIME @CARP_NOT $GRAND_TOTAL/;
#use Scalar::Util 'blessed';
use GT::File::Tools qw/mkpath dirname/;
use Carp;
@CARP_NOT = 'GT::Plugins';
# Inherit from base class for debug and error methods
@Plugins::SocialMedia::ISA = qw(GT::Base);
# Your code begins here.
# PLUGIN HOOKS
# ===================================================================
sub post_twitter {
my $link = shift;
$link = format_link($link);
$link || return;
# When no authentication is required:
my $nt = Net::Twitter->new(legacy => 0);
my $consumer_key = "u4xwsqHZBKrdWYPrKCm8Lw";
my $consumer_secret = "vjDF6FjeoPJW0WVwgqMEJeuJzilgSIu5QbPGQnWrMI";
my $token = "1921299666-fMicJMBunBjgBb4ieszHo6tYV0mQcbbaMZU5wSB";
my $token_secret = "Ko9gPpBaLxqQj6u68EWdlgnPinGSseVzrzUvytWric";
#return { error => 'error posting...unknown' };
my $tags = $IN->param('twitter_hash_tags');
$tags =~ s/\s+//g;
my @tags = split(',',$tags);
my $newtags;
for (@tags) {
$newtags .= ' #' . $_;
}
my $post_title = $IN->param('twitter_status');
my $len = length $link->{detailed_url};
$len = 140 - 5 - $len;
$post_title = substr($post_title,0,$len) . "..." if (length $post_title > $len);
$post_title .= " " . $link->{detailed_url};
$post_title .= $newtags;
# As of 13-Aug-2010, Twitter requires OAuth for authenticated requests
$nt = Net::Twitter->new(
traits => [qw/API::RESTv1_1/],
consumer_key => $consumer_key,
consumer_secret => $consumer_secret,
access_token => $token,
access_token_secret => $token_secret,
);
my $result;
my $res = eval { $result = $nt->update($post_title) };
if ( my $err = $@ ) {
die $@ unless $err and $err->isa('Net::Twitter::Error');
#warn "HTTP Response Code: ", $err->code, "\n",
#"HTTP Message......: ", $err->message, "\n",
#"Twitter error.....: ", $err->error, "\n";
$result->{error} = $err->error;
}
return $result;
}
sub post_facebook {
# -------------------------------------------------------------------
my $access_token = shift;
my $id = shift;
my $link = format_link($id);
if ($link->{facebook_hashtags}) {
$link->{Description} .= " ";
$link->{Description} .= $link->{facebook_hashtags};
}
#Publish to a facebook page as admin
my $cfg = Links::Plugins::get_plugin_user_cfg('Auth_Facebook');
my $result = facebook_graph_api('/' . $cfg->{fb_fanpageid} . '/links',{
link => "http://www.slowtwitch.com/temp/$id.html",
#link => $link->{detailed_url},
message => $link->{Description},
picture => $link->{Picture},
access_token => $access_token,
method => 'post'
});
return $result;
}
sub facebook_graph_api {
# -------------------------------------------------------------------
my $uri = new URI('https://graph.facebook.com/' . shift);
$uri->query_form(shift);
require GT::WWW;
my $www = GT::WWW->get("$uri");
my $resp = $www->content;
return defined $resp ? decode_json($resp) : undef;
}
sub format_link {
# -------------------------------------------------------------------
my $link = shift;
if ($link =~ /^(\d+)$/) {
$link = $DB->table('Links')->get($link);
}
$link or return;
$link = Links::SiteHTML::tags('link',$link);
my $len = length $link->{detailed_url};
$len = 140 - 5 - $len;
$link->{Description} = substr($link->{Description},0,$len) . "..." if (length $link->{Description} > $len);
my @cats = $DB->table('Category', 'CatLinks')->select('Category.Full_Name', { 'CatLinks.LinkID' => $link->{ID} })->fetchall_list;
$link->{Category} = join "\n", sort @cats;
use Plugins::SlideShow;
my $paths = Plugins::SlideShow::generate_paths($link->{ID});
$link->{image_paths} = $paths;
my $img = $link->{facebook_published_image} || "Image1";
$link->{Picture} = $paths->{$img . '_largest_path'} if ($paths->{$img . '_largest_path'});
return $link;
}
sub publish_it {
# -------------------------------------------------------------------
if ($IN->param('build')) {
my $linkid = $IN->param('linkid');
my ($twitter, $fb);
use Time::HiRes;
#Time::HiRes::sleep(5); #.1 seconds
#print $IN->header;
$IN->param('t','dev'); #FIXME
#print $IN->header;
build_it($linkid);
my $hash = {};
#print Links::user_page('add_success_publish.html', { success => '1', built => 1, twitter => $twitter, %$hash });
#return;
if ($IN->param('post_facebook')) {
if ($IN->param('post_twitter')) {
my $res = post_twitter($linkid);
if ($res->{id}) {
$DB->table('Links')->update({ twitter_published => $res->{id} }, { ID => $linkid });
$hash->{twitter_published} = 1;
}
else {
$DB->table('Links')->update({ twitter_published_message => $res->{error} }, { ID => $linkid });
$hash->{twitter_published_message} = $res->{error} if ($res->{error});
}
}
use Plugins::Auth_Facebook;
Plugins::Auth_Facebook::user_auth($linkid);
return;
}
elsif ($IN->param('post_twitter')) {
my $res = post_twitter($linkid);
if ($res->{id}) {
$DB->table('Links')->update({ twitter_published => $res->{id} }, { ID => $linkid });
$hash->{twitter_published} = 1;
}
else {
$DB->table('Links')->update({ twitter_published_message => $res->{error} }, { ID => $linkid });
$hash->{twitter_published_message} = $res->{error} if ($res->{error});
}
}
$IN->param('t','dev'); #FIXME
print $IN->header;
print Links::user_page('add_success_publish.html', { success => '1', built => 1, twitter => $twitter, %$hash });
}
else {
print $IN->header;
print Links::user_page('error.html', { error => 'no error' });
}
}
sub build_it {
# -------------------------------------------------------------------
#
my $linkid = shift || return;
my $unix_time = $CFG->{last_build} ? $CFG->{last_build} : time;
Links::init_date();
my $time = GT::Date::date_get($unix_time - $CFG->{date_offset} * 3600, '%yyyy%-%mm%-%dd% %HH%:%MM%:%ss%');
=tag
# Do any backups.
_build_backup();
# Update isNew, isCool, isPopular flags.
_build_reset_hits();
_build_new_flags();
_build_changed_flags();
_build_cool_flags();
# Build Home Page.
$PLG->dispatch('create_home', \&_build_home, {});
=cut
=tag
# Build New Page.
$PLG->dispatch('create_new', \&_build_new, {});
# Build Cool Page.
$PLG->dispatch('create_cool', \&_build_cool, {});
# Build Ratings Page.
$PLG->dispatch('create_ratings', \&_build_ratings, {});
=cut
# Build Changed Detailed Page.
$PLG->dispatch('create_detailed_changed', \&_build_detailed, GT::SQL::Condition->new('Links.ID', '=', $linkid));
=tag
# Build Changed Category Pages.
$PLG->dispatch('create_category_changed', \&_build_category, GT::SQL::Condition->new('Timestmp', '>', $time));
$CFG->{last_build} = time;
$CFG->save;
=cut
}
sub get_path {
# -------------------------------------------------------------------
#
my $field = shift;
my $filefield = $field . "_largest_path";
my $link = GT::Template->tags();
if (!$link->{$filefield}) {
$filefield = $field . "_medium_path";
}
return $link->{$filefield};
}
# ------------------------------------------------------------------
# MISC BUILD functions
# ------------------------------------------------------------------
sub _build_home {
# ------------------------------------------------------------------
# Generate the home page.
#
_time_start();
my $index = $CFG->{build_home} || $CFG->{build_index};
my $page = "$CFG->{build_root_path}/$index";
print $USE_HTML
? qq'Building <a href="$CFG->{build_root_url}/$index" target="_blank">Home Page</a>...\n'
: qq'Building Home Page...\n';
my $fh = _open_write($page);
print $fh Links::Build::build(home => {});
close $fh;
my $perms = oct $CFG->{build_file_per};
chmod $perms, $page;
_display_time();
}
sub _build_detailed {
# ------------------------------------------------------------------
# Generate one html page per link.
#
require Links::Tools;
my ($cond, $cust_page, $cust_limit);
if (ref $_[0] eq 'HASH') {
$cust_page = $_[0]->{page};
$cust_limit = $_[0]->{limit};
}
else {
$cond = shift;
}
unless ($CFG->{build_detailed}) {
print "Skipping Detailed Build (disabled).\n\n";
return;
}
_time_start();
#print "Building Detailed pages...\n";
# Only build validated links
$cond ||= GT::SQL::Condition->new;
$cond->add(VIEWABLE);
# Loop through, building 1000 at a time
my ($limit, $offset, $count, $second_pass) = (1000, 0, 0);
my $rel = $DB->table(qw/Links CatLinks Category/);
#print "\t";
my $Links = $DB->table('Links');
while () {
# Links can be in multiple categories, make sure their detailed pages are only built once
$rel->select_options("GROUP BY LinkID") if $CFG->{build_detail_format} eq '%ID%';
$rel->select_options("ORDER BY LinkID");
if ($cust_page or $cust_limit) {
last if $second_pass++;
$rel->select_options(sprintf "LIMIT %d OFFSET %d", $cust_limit, ($cust_page-1) * $cust_limit);
}
else {
$rel->select_options(sprintf "LIMIT %d OFFSET %d", $limit, $offset*$limit);
}
my %links_cols = %{$Links->cols};
# Only select Category columns that don't conflict with Links columns.
my @cat_cols = grep !$links_cols{$_}, keys %{$DB->table('Category')->cols};
my $sth = $rel->select('Links.*', @cat_cols, 'CategoryID' => $cond);
last unless $sth->rows;
while (my $link = $sth->fetchrow_hashref) {
my $format = $Links->detailed_url($link);
$format = "temp/" . $link->{ID} . ".html"; #FIXME
my $page = "$CFG->{build_detail_path}/$format";
my $url = "$CFG->{build_detail_url}/$format";
{
my $fh = _open_write($page);
print $fh Links::Build::build(detailed => $link);
}
my $perms = oct $CFG->{build_file_per};
chmod $perms, $page;
=tag
$USE_HTML ?
print qq'<a href="$url" target="_blank">$link->{ID}</a> ' :
print "$link->{ID} ";
print "\n\t" if ++$count % 20 == 0;
=cut
}
$offset++;
}
=tag
print "\n";
_display_time();
=cut
}
sub _build_category {
# ------------------------------------------------------------------
# Generate the category pages.
#
my ($cond, $cust_page, $cust_limit);
if (ref $_[0] eq 'HASH') {
$cust_page = $_[0]->{page};
$cust_limit = $_[0]->{offset};
$cond = {};
}
else {
$cond = shift;
}
_time_start();
print "Building Category pages...\n\n";
my $Cat = $DB->table('Category');
my $CatLinks = $DB->table('Links', 'CatLinks');
$Cat->select_options('ORDER BY Full_Name');
if (defined $cust_page and $cust_limit) {
$Cat->select_options(sprintf "LIMIT %d OFFSET %d", $cust_limit, ($cust_page-1)*$cust_limit);
}
my $sth = $Cat->select(ID => Full_Name => $cond);
while (my ($id, $name) = $sth->fetchrow_array) {
my $clean_name = $Cat->as_url($name);
my $page = $CFG->{build_root_path} . "/" . $clean_name . '/' . $CFG->{build_index};
my $url = $CFG->{build_root_url} . "/" . $clean_name . '/' . $CFG->{build_index};
print $USE_HTML
? "\tBuilding category <a href='$url' target='_blank'>$name</a>...\n"
: "\tBuilding category $name...\n";
my $total = $CatLinks->count({ 'CatLinks.CategoryID' => $id }, VIEWABLE);
print "\t\tLinks: $total\n";
# Do sub-pages if requested.
if ($CFG->{build_span_pages}) {
my $lpp = $CFG->{build_links_per_page} || 25;
my $num_pages = int($total / $lpp);
$num_pages++ if $total % $lpp;
# Create the main page.
{
my $fh = _open_write($page);
print $fh Links::Build::build(category => { id => $id, nh => 1, mh => $lpp });
}
my $perms = oct $CFG->{build_file_per};
chmod $perms, $page;
# Create the sub pages.
for (2 .. $num_pages) {
$page = "$CFG->{build_root_path}/$clean_name/$CFG->{build_more}$_$CFG->{build_extension}";
$url = "$CFG->{build_root_url}/$clean_name/$CFG->{build_more}$_$CFG->{build_extension}";
print "\t\tBuilding subpage: " . ($USE_HTML
? "<a href='$url' target='_blank'>$_</a>\n"
: "$_\n"
);
{
my $fh = _open_write($page);
print $fh Links::Build::build(category => { id => $id, nh => $_, mh => $lpp });
}
chmod $perms, $page;
}
}
else {
{
my $fh = _open_write($page);
print $fh Links::Build::build(category => { id => $id });
}
my $perms = oct $CFG->{build_file_per};
chmod $perms, $page;
}
print "\tDone\n\n";
}
_display_time("Finished building categories");
}
sub _build_backup {
# ------------------------------------------------------------------
# Create a backup file in our backup directory.
#
if (! $CFG->{build_use_backup}) {
print "Creating backup file... skipped\n\n";
return;
}
_time_start();
print "Creating backup file...\n";
require Links::Import::S2BK;
my $max_keep = 7;
my $root = $CFG->{admin_root_path} . '/backup';
my $filename = 'BACKUP';
for my $n (reverse 0 .. $max_keep) {
my $oldname = join '.', $filename, $n || ();
my $newname = join '.', $filename, $n+1;
if (-e "$root/$oldname") {
rename "$root/$oldname", "$root/$newname" or print "\tCouldn't rename '$root/$oldname' -> '$root/$newname': $!";
}
}
Links::Import::S2BK::import({ source => "$CFG->{admin_root_path}/defs", destination => "$root/$filename", delimiter => "\t" }, sub { print "\n\tWARNING: @_\n" }, sub { die @_ }, sub { print "\n\tWARNING: @_\n" }, sub { });
_display_time();
}
sub _build_reset_hits {
# ------------------------------------------------------------------
# Updates the What's New flags.
#
_time_start();
print "Resetting hits and rates...\n";
my $ret = Links::Build::build(reset_hits => shift || {});
_display_time();
return $ret;
}
sub _build_new_flags {
# ------------------------------------------------------------------
# Updates the What's New flags.
#
_time_start();
print "Updating new flags...\n";
my $ret = Links::Build::build(new_flags => shift || {});
_display_time();
return $ret;
}
sub _build_changed_flags {
# ------------------------------------------------------------------
# Updates the isChanged flags.
#
_time_start();
print "Updating changed flags...\n";
my $ret = Links::Build::build(changed_flags => shift || {});
_display_time();
return $ret;
}
sub _build_cool_flags {
# ------------------------------------------------------------------
# Updates the What's Cool flags.
#
_time_start();
print "Updating Cool Flags...\n";
my $ret = Links::Build::build(cool_flags => shift || {});
_display_time();
return $ret;
}
sub _time_start {
# ------------------------------------------------------------------
# Start a timer.
#
$TIME_START = time;
}
sub _display_time {
# ------------------------------------------------------------------
# Return time results.
#
my $message = shift || 'Done';
return;
printf "%s (%.2fs)\n\n", $message, time - $TIME_START;
}
sub _header {
# ------------------------------------------------------------------
# Print intro.
#
my ($msg, $msg2, $refresh, $started) = @_;
my $time = scalar localtime;
$refresh ||= '';
$TOTAL_TIME = $started || time;
$refresh &&= "<meta http-equiv='Refresh' content='2; URL=$refresh'>";
if ($USE_HTML) {
print $IN->header(-nph => $CFG->{nph_headers});
print <<BUILDING;
<html>
<head>
$refresh
<title>Building HTML Pages</title>
<body bgcolor="white">
BUILDING
print Links::header("Building HTML Pages: $msg", $msg2, 0);
print <<STARTED;
<pre>Started at $time.
STARTED
}
else {
print "Started at $time.\n\nBuilding HTML pages...\n\n";
}
}
sub _footer {
# ------------------------------------------------------------------
# Print the footer.
#
my $end = time;
my $elapsed = sprintf "%.2f", $end - $TOTAL_TIME;
print "All done. Total time: (${elapsed}s)\n";
print "</pre></body></html>" if $USE_HTML;
}
sub _open_write {
# -----------------------------------------------------------------------------
# Opens a file for writing (overwriting anything already there), and returns a
# filehandle reference. Dies with a more user-friendly error then Links::fatal
# if the open fails. Can take a second argument which, if true, will cause the
# function _not_ to attempt to make the containing directory.
#
my ($page, $nomkdir) = @_;
unless ($nomkdir) {
mkpath(dirname($page), oct $CFG->{build_dir_per});
}
my $fh = \do { local *FH; *FH };
open $fh, "> $page" and return $fh;
my $error = "$!";
my $user = eval { getpwuid($>) } || 'webserver';
if ($error =~ /permission/i) {
print "\n\n<b>ERROR:</b> Unable to open '$page': $error\n\n";
if (-e $page) {
print <<HELP;
This means that the user '$user' is not able to overwrite the existing file.
Please make sure you have set the permissions in the setup to 0666 if you plan
to build from both the web and shell at the same time.
HELP
}
else {
print <<HELP;
This means that the user '$user' is not able to create a file in your pages
directory. Please chmod the main directory 0777 so the program can create the
file.
HELP
}
croak "Debug information";
}
else {
croak "Unable to open: '$page': $error";
}
}
1;

View File

@ -0,0 +1,703 @@
# ==================================================================
# Plugins::UI - Auto Generated Program Module
#
# Plugins::UI
# Author : Bao Phan
# Version : 1.0
# Updated : Tue Mar 15 12:59:20 2016
#
# ==================================================================
#
package Plugins::UI;
# ==================================================================
use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/:objects :payment/;
use Links::Build;
use Links::SiteHTML;
use constants
VIDEO => 'video',
PHOTO => 'photo',
ARTICLE => 'article'
;
# Inherit from base class for debug and error methods
@Plugins::UI::ISA = qw(GT::Base);
require Plugins::SlideShow;
require Plugins::ConvertVideo;
require GT::SQL::Condition;
require GT::Date;
sub cat_url {
my $full_name = shift || return;
return "$CFG->{build_root_url}/" . $DB->table('Category')->as_url($full_name) . "/" . ($CFG->{build_index_include} ? $CFG->{build_index} : '');
}
sub update_featured_links {
my ($type, $id, $add) = @_;
return if $USER->{Status} ne 'Administrator';
return unless $id and $type;
return if $type !~ /^(article|photo|video)$/i;
my $name = $type eq 'article' ? 'featured_articles' : 'featured_photos';
my $ids = $CFG->{$name} || [];
my (@ids, $changed);
my %ids = map { $_ => 1 } @$ids;
if ($add) {
if ($ids{$id}) {
@ids = @$ids;
}
else {
@ids = ($id, @$ids);
my $hits = scalar @ids;
if ($type eq 'article' and $hits > 4) {
pop @ids;
}
elsif ($type ne 'article' and $hits > 2) {
pop @ids;
}
$changed = 1;
}
}
elsif ($ids{$id}) {
@ids = map $_, grep { $_ != $id } @$ids;
$changed = 1;
}
return unless $changed;
$CFG->{$name} = \@ids;
$CFG->save;
return;
}
sub is_featured {
my ($type, $id) = @_;
return unless $id and $type;
return if $type !~ /^(article|photo|video)$/i;
my $name = $type eq 'article' ? 'featured_articles' : 'featured_photos';
my $ids = $CFG->{$name} || [];
my %ids = map { $_ => 1 } @$ids;
return $ids{$id} ? 1 : 0;
}
sub fetch_categories {
my $ids = shift;
$ids = ref $ids ? @$ids : [$ids] if $ids;
my $tab = $DB->table('Category');
$tab->select_options('ORDER BY Name');
my $cond = GT::SQL::Condition->new( CatDepth => '=' => 0);
$cond->add(ID => '=' => $ids) if $ids;
my $cats = $tab->select($cond)->fetchall_hashref;
foreach (@$cats) {
$_->{URL} = "$CFG->{build_root_url}/" . $tab->as_url($_->{Full_Name}) . "/" . ($CFG->{build_index_include} ? $CFG->{build_index} : '');
}
return $cats;
}
sub fetch_links {
my %args = @_;
return unless %args;
my $maxhits = $args{max_hits} || 1;
my $cond = new GT::SQL::Condition;
my $url = $CFG->{build_detail_url};
my (@ids, %paging);
my $tab_cat = $DB->table('Category');
my $tab_lnks = $DB->table('Links');
my $tab_catlnks = $DB->table(qw/Links CatLinks Category/);
if ($args{type}) {
$cond->add(Type => '=' => $args{type});
$tab_catlnks->select_options("GROUP BY LinkID", "ORDER BY Add_Date DESC", "LIMIT $maxhits");
}
elsif ($args{ids}) {
if (ref $args{ids} eq 'ARRAY') {
@ids = @{$args{ids}};
}
else {
@ids = split(/\,|\r?\n/, $args{ids});
}
return unless scalar @ids;
$cond->add(LinkID => '=' => \@ids);
$tab_catlnks->select_options("ORDER BY Add_Date DESC");
$tab_catlnks->select_options("LIMIT $maxhits") if $args{max_hits};
}
elsif ($args{category}) {
my $category = $tab_cat->get($args{category});
return unless $category;
$cond->add(Full_Name => 'like' => $category->{Full_Name} . '%');
$tab_catlnks->select_options("ORDER BY Add_Date DESC", "LIMIT $maxhits");
}
elsif ($args{tag} and $args{tag} =~ /^(?:swim|bike|run)$/i) {
my $vars = GT::Template->vars;
my $tag = lc $args{tag};
$url .= "/$tag";
$paging{max_hits} = $args{max_hits} || 25;
$paging{current_page} = $vars->{nh} || 1;
$paging{page} = $args{url} || ($tag . '/');
my $offset = $paging{current_page} == 1 ? 0 : ($paging{current_page} - 1) * $paging{max_hits};
$cond->add('tag_' . $tag => '=' => 1);
$tab_catlnks->select_options("GROUP BY LinkID", "ORDER BY Add_Date DESC", "LIMIT $paging{max_hits} OFFSET $offset");
}
elsif ($args{link_type} and $args{link_type} =~ /^(?:photo|video)$/i) {
my $vars = GT::Template->vars;
$url .= "/" . ($args{link_type} eq 'video' ? 'Videos' : 'Photos');
$paging{max_hits} = $args{max_hits} || 25;
$paging{current_page} = $vars->{nh} || 1;
$paging{page} = ($args{link_type} eq 'video' ? 'Videos' : 'Photos') . '/';
my $offset = $paging{current_page} == 1 ? 0 : ($paging{current_page} - 1) * $paging{max_hits};
$cond->add(Link_Type => '=' => $args{link_type});
$tab_catlnks->select_options("GROUP BY LinkID", "ORDER BY Add_Date DESC", "LIMIT $paging{max_hits} OFFSET $offset");
}
else {
$tab_catlnks->select_options("GROUP BY LinkID", "ORDER BY Add_Date DESC", "LIMIT $maxhits");
}
my $links = ($tab_catlnks->select(qw/Links.* Name Full_Name/, $cond) or die $GT::SQL::error)->fetchall_hashref;
return unless scalar @$links;
foreach my $l (@$links) {
$l->{detailed_url} = "$url/" . $tab_lnks->detailed_url($l->{ID}) if $CFG->{build_detailed};
$l->{URL} = "$CFG->{build_root_url}/" . $tab_cat->as_url($l->{Full_Name}) . "/" . ($CFG->{build_index_include} ? $CFG->{build_index} : '');
$l->{thumbnail_url} = fetch_thumbnail($l);
}
if (scalar @ids and !$args{db}) {
my @links_output;
my %links = map { $_->{ID} => $_ } @$links;
foreach my $id (@ids) {
push @links_output, $links{$id} if $links{$id};
}
return \@links_output;
}
elsif (
($args{link_type} and $args{link_type} =~ /^(?:photo|video)$/) or
($args{tag} and $args{tag} =~ /^(?:swim|bike|run)$/)
) {
$paging{num_hits} = $tab_lnks->select('COUNT(*)', $cond)->fetchrow;
my @features;
if ($paging{current_page} == 1) {
@features = splice @$links, 0, 3;
}
return { loop => $links, features => \@features, paging => \%paging };
}
else {
return $links;
}
}
sub fetch_category {
my $catid = shift || return;
return $DB->table('Category')->get($catid);
}
sub fetch_widget {
my $id = shift || return;
my $tab = $DB->table('Widgets');
my $widget = $tab->get($id);
return unless $widget;
if ($widget->{Image}) {
my $fh = $tab->file_info('Image', $widget->{ID});
$widget->{Image_URL} = '/images/widgets/' . $fh->File_RelativeURL;
}
return $widget;
}
sub fetch_widgets {
my ($page, $catid) = @_;
return unless $page;
my $tab_pgwidgets = $DB->table(qw/Widgets PageWidgets/);
$tab_pgwidgets->select_options('ORDER BY Sort_Pos');
my $widgets = [];
if ($catid =~ /^\d+$/) {
$widgets = $tab_pgwidgets->select(qw/Widgets.* Sort_Pos/, { Page => $catid })->fetchall_hashref;
}
unless (scalar @$widgets) {
$widgets = $tab_pgwidgets->select(qw/Widgets.* Sort_Pos/, { Page => $page })->fetchall_hashref;
}
my $tab = $DB->table('Widgets');
foreach my $w (@$widgets) {
next unless $w->{Image};
my $fh = $tab->file_info('Image', $w->{ID});
next unless $fh;
$w->{Image_URL} = '/images/widgets/' . $fh->File_RelativeURL;
}
return $widgets;
}
sub generate_widget {
my $id = shift || return;
my $widget = fetch_widget($id);
return unless $widget;
return Links::SiteHTML::display('include_single_widget', $widget);
}
sub friendly_date {
my ($date, $timestmp, $format) = @_;
return unless $date;
my $days = GT::Date::date_diff(GT::Date::date_get(time, '%yyyy%-%mm%-%dd%'), $date);
unless ($days) {
my $time = GT::Date::timelocal(GT::Date::parse_format($timestmp, "%yyyy%-%mm%-%dd% %HH%:%MM%:%ss%"));
my $secs = time - $time;
return unless $secs;
$date = $timestmp;
return "$secs seconds ago" if $secs < 60;
my $mins = int($secs / 60);
return "$mins minutes ago" if $mins < 60;
my $hours = int($secs / 3600);
return $hours . ($hours > 1 ? " hours ago" : " hour ago");
}
else {
my $time = GT::Date::timelocal(GT::Date::parse_format($date, "%yyyy%-%mm%-%dd%"));
$date = $time;
return ($format or $days > 7)
? GT::Date::date_get($date, $format || "%mmm% %dd%, %yyyy%")
: $days . ($days > 1 ? " days ago" : " day ago");
}
}
sub retrieve_param {
my ($field, $count) = @_;
return unless $field;
$count ||= 1;
my $vars = GT::Template->vars;
if ($field eq 'Image_description') {
return $vars->{"Image${count}_description"};
}
elsif ($field =~ /^Image_(.*)$/) {
return $vars->{"Image${count}_$1"} || $vars->{"Image${count}_path"};
}
else {
return $vars->{"$field$count"};
}
}
sub fetch_thumbnail {
my $link = shift || return;
if ($link->{Link_Type} eq VIDEO) {
if ($link->{Thumbnail_URL} and $link->{Thumbnail_URL} ne 'http://') {
return { small => $link->{Thumbnail_URL} };
}
else {
my $field = Plugins::ConvertVideo::get_file_path($link->{ID}, "thumbnail_file_field");
return $field->{thumbnail_file_field_path}
? {
small => $field->{thumbnail_file_field_path},
medium => $field->{thumbnail_file_field_path},
large => $field->{thumbnail_file_field_path},
largest => $field->{thumbnail_file_field_path},
}
: undef;
}
}
else {
my $slideshow = Plugins::SlideShow::generate_paths($link->{ID});
if ($slideshow and $slideshow->{image_loop}) {
return {
small => $slideshow->{image_loop}->[0]{_thumbnail_path},
medium => $slideshow->{image_loop}->[0]{_medium_path},
large => $slideshow->{image_loop}->[0]{_large_path},
largest => $slideshow->{image_loop}->[0]{_largest_path}
};
}
}
}
sub slideshow_url {
my $url = shift || return;
$url =~ s,^$CFG->{build_detail_url},$CFG->{build_detail_url}/Photos,;
return $url;
}
sub rewrite_breadcrumbs {
my ($title_loop, $mode) = @_;
return unless ref $title_loop;
my @loop;
foreach my $i (0 .. scalar @$title_loop - 1) {
my $item = $title_loop->[$i];
if ($i == 1) {
if ($item->{Name} =~ /rd\s*aids/i) {
push @loop, {
Name => "Races",
URL => "$CFG->{build_root_url}/Races/index.html"
};
}
elsif ($mode) {
push @loop, {
Name => $mode eq 'photo' ? 'Photo Galleries' : 'Videos',
URL => "$CFG->{build_root_url}/" . ($mode eq 'photo' ? 'Photos' : 'Videos') . "/index.html"
};
}
elsif ($item->{Name} !~ /home|bike\s*fit|products|races|articles|photos|videos|coaching|podcast|privacy|about|agreement/i) {
push @loop, {
Name => "Articles",
URL => "$CFG->{build_root_url}/Articles/index.html"
};
}
}
push @loop, $item;
}
return \@loop;
}
sub build_category {
my $opts = shift;
$opts->{id} ||= $IN->param('ID');
return @_ unless $opts->{id};
my $cfg = Links::Plugins->get_plugin_user_cfg('UI');
return @_ unless $cfg and $cfg->{merge_categories};
my %ids = map { $_ => 1 } split(/\s*,\s*/, $cfg->{merge_categories});
return @_ unless $ids{$opts->{id}};
GT::Plugins->action( STOP );
my $cat_db = $DB->table('Category');
my $link_db = $DB->table('Links');
my $catlink_db = $DB->table('Links', 'CatLinks');
my $related_db = $DB->table('CatRelations');
$Links::Build::GRAND_TOTAL ||= Links::Build::_grand_total();
if (ref $opts ne 'HASH') {
Links::debug("Invalid argument passed to build_category: $opts") if $Links::DEBUG;
return @_;
}
# Load our category info.
my $category;
if ($opts->{id}) {
$category = $cat_db->get($opts->{id}, 'HASH');
if (! $category) {
Links::debug("Invalid category id passed to build_category: $opts->{id}") if $Links::DEBUG;
return;
}
}
# Get our options.
$opts->{mh} = exists $opts->{mh} ? $opts->{mh} : $CFG->{build_span_pages} ? $CFG->{build_links_per_page} : 5000;
$opts->{nh} = exists $opts->{nh} ? $opts->{nh} : 1;
$opts->{sb} = exists $opts->{sb} ? $opts->{sb} : $CFG->{build_sort_order_category};
$opts->{so} = exists $opts->{so} ? $opts->{so} : '';
if ($opts->{sb} =~ /\b(?:asc|desc)\b/i) {
$opts->{so} = '';
}
$opts->{cat_sb} = exists $opts->{cat_sb} ? $opts->{cat_sb} : $CFG->{build_category_sort};
$opts->{cat_so} = exists $opts->{cat_so} ? $opts->{cat_so} : '';
if ($opts->{cat_sb} =~ /\b(?:asc|desc)\b/i) {
$opts->{cat_so} = '';
}
# Figure out the template set to use.
$category->{Category_Template} ||= $cat_db->template_set($category->{ID});
# Get our output vars.
my %tplvars = (
%$category,
category_id => $category->{ID},
category_name => $category->{Full_Name},
header => $category->{Header},
footer => $category->{Footer},
meta_name => $category->{Meta_Description},
meta_keywords => $category->{Meta_Keywords},
description => $category->{Description},
random => int rand 10000,
random1 => int rand 10000,
random2 => int rand 10000,
random3 => int rand 10000
);
# Clean up the name.
my $clean_name = $cat_db->as_url($category->{Full_Name});
my $build_title = $category->{Full_Name};
$build_title .= '/' . Links::language('LINKS_PAGE', $opts->{nh}) if $opts->{nh} and $opts->{nh} > 1;
$tplvars{title_loop} = Links::Build::build('title', $build_title);
$tplvars{title_linked} = sub { Links::Build::build('title_linked', $build_title) };
$tplvars{title} = sub { Links::Build::build('title_unlinked', $build_title) };
$tplvars{category_name_escaped} = GT::CGI->escape($category->{Full_Name});
$tplvars{category_clean} = $tplvars{title};
($tplvars{category_short}) = $tplvars{category_name} =~ m|([^/]+)$|;
# CUSTOMIZED: show all links in a category as well as subcategories
my $categories = $cat_db->children($category->{ID});
push @$categories, $category->{ID};
my $cond = GT::SQL::Condition->new(
CategoryID => '=' => $categories,
isValidated => '=' => 'Yes'
);
# "Optional" payment categories are a hassle, as we have to do two selects,
# then balance out the mh/nh variables between the two.
my ($optional_sth, $sth);
my @select_options;
push @select_options, "ORDER BY $opts->{sb} $opts->{so}" if $opts->{sb};
# Load payment info if payment is enabled. Change sort order by paid links
# first then free links if payment for this category is optional. If payment
# is required, we need to remove unpaid links
if ($CFG->{payment}->{enabled}) {
require Links::Payment;
my $payment_info = Links::Payment::cat_payment_info($opts->{id});
if ($payment_info->{mode} == OPTIONAL and $CFG->{build_sort_paid_first}) {
my $paycond = GT::SQL::Condition->new($cond);
$paycond->add(ExpiryDate => '>=' => time, ExpiryDate => '<=' => UNLIMITED);
my $offset = ($opts->{nh} - 1) * $opts->{mh};
$catlink_db->select_options(@select_options);
$catlink_db->select_options("LIMIT $opts->{mh} OFFSET $offset");
$optional_sth = $catlink_db->select('Links.*', $paycond);
$cond->add(ExpiryDate => '=' => FREE);
}
else {
# 1) This is an else (instead of elsif ($payment_info->{mode} == REQUIRED)) because the
# run-time count updating code cannot efficiently take category settings into account
# as doing so requires either subselects (which older MySQL doesn't support), or a fair
# bit of Perl code; a single fast count to determine whether the check is necessary
# won't work. The end result is that counts would be off.
# 2) Even if this was an elsif, we can't include ExpiryDate <= UNLIMITED (to exclude
# free links) because links being free is the default for imported, upgraded, and
# admin-added links, which we don't want to exclude from REQUIRED categories.
$cond->add(ExpiryDate => '>=' => time);
}
}
my @results;
my ($paid_hits, $paid_rows, $offset, $max_hits) = (0, 0, ($opts->{nh} - 1) * $opts->{mh}, $opts->{mh});
if ($optional_sth) {
push @results, @{$optional_sth->fetchall_hashref};
$paid_rows = $optional_sth->rows;
$paid_hits = $catlink_db->hits;
if ($paid_rows == $opts->{mh}) {
$offset = $max_hits = 0;
}
elsif ($paid_rows > 0) {
$offset = 0;
$max_hits = $opts->{mh} - $paid_rows;
}
else {
$offset -= $paid_hits;
}
}
my $hits;
# Select links from required categories, not-accepted categories, and optional
# categories whose paid hits haven't filled the page
if ($max_hits) { # $max_hits will be 0 when mh paid links are already listed
$catlink_db->select_options(@select_options);
$catlink_db->select_options("LIMIT $max_hits OFFSET $offset");
my @ids = map $_->[0], @{$catlink_db->select('DISTINCT LinkID', $cond)->fetchall_arrayref};
$link_db->select_options(@select_options);
my $sth = $link_db->select({ ID => \@ids });
push @results, @{$sth->fetchall_hashref};
$hits = $catlink_db->hits;
}
else {
$hits = $catlink_db->count($cond);
}
my $numlinks = $tplvars{total} = $hits + $paid_hits;
$tplvars{total_optional_paid} = $paid_hits;
# Get the links.
$link_db->add_reviews(\@results);
my @links_loop = map Links::SiteHTML::tags('link', $_, undef) => @results;
$tplvars{links_loop} = \@links_loop;
$tplvars{links_count} = @links_loop;
my $links;
$tplvars{links} = sub {
return $links if defined $links;
$links = '';
for my $link (@results) {
$link->{Category_Template} = $category->{Category_Template} if $category->{Category_Template};
$links .= Links::SiteHTML::display('link', $link);
}
return $links;
};
# Get the subcategories and related categories as either Yahoo style (integrated) or
# separated into two outputs..
my @cat_loop;
$tplvars{category_loop} = \@cat_loop;
if ($CFG->{build_category_yahoo}) {
my @subcat_ids = $cat_db->select(ID => { FatherID => $category->{ID} })->fetchall_list;
my %related_ids = $related_db->select(qw/RelatedID RelationName/ => { CategoryID => $category->{ID} })->fetchall_list;
if (@subcat_ids or keys %related_ids) {
$cat_db->select_options("ORDER BY $opts->{cat_sb} $opts->{cat_so}") if $opts->{cat_sb};
my $sth = $cat_db->select({ ID => [@subcat_ids, keys %related_ids] });
my @rel_loop;
while (my $cat = $sth->fetchrow_hashref) {
$cat->{URL} = "$CFG->{build_root_url}/" . $cat_db->as_url($cat->{Full_Name}) . "/" . ($CFG->{build_index_include} ? $CFG->{build_index} : '');
$cat->{RelationName} = '';
if (exists $related_ids{$cat->{ID}}) {
$cat->{Related} = 1;
$cat->{RelationName} = $related_ids{$cat->{ID}};
# Relations with a custom name need to be re-sorted
if ($cat->{RelationName}) {
push @rel_loop, $cat;
next;
}
}
push @cat_loop, $cat;
}
# Re-sort related categories using their RelationName rather than the related
# category's name
RELATION: while (my $cat = pop @rel_loop) {
for (my $i = 0; $i < @cat_loop; $i++) {
my $name = $cat_loop[$i]->{RelationName} ? $cat_loop[$i]->{RelationName} : $cat_loop[$i]->{Name};
if (lc $cat->{RelationName} lt lc $name) {
splice @cat_loop, $i, 0, $cat;
next RELATION;
}
}
push @cat_loop, $cat;
}
my $print_cat;
$tplvars{category} = sub {
return $print_cat if defined $print_cat;
return $print_cat = Links::SiteHTML::display('print_cat', [$category, @cat_loop]);
};
}
else {
$tplvars{category} = '';
}
}
else {
# Separate the output.
$cat_db->select_options("ORDER BY $opts->{cat_sb} $opts->{cat_so}") if $opts->{cat_sb};
$sth = $cat_db->select({ FatherID => $category->{ID} });
while (my $cat = $sth->fetchrow_hashref) {
$cat->{URL} = "$CFG->{build_root_url}/" . $cat_db->as_url($cat->{Full_Name}) . "/" . ($CFG->{build_index_include} ? $CFG->{build_index} : '');
push @cat_loop, $cat;
}
if (@cat_loop) {
my $print_cat;
$tplvars{category} = sub {
return $print_cat if defined $print_cat;
return $print_cat = Links::SiteHTML::display('print_cat', [$category, @cat_loop]);
};
}
else {
$tplvars{category} = '';
}
$tplvars{related} = '';
$tplvars{related_loop} = [];
my %related_ids = $related_db->select(qw/RelatedID RelationName/ => { CategoryID => $category->{ID} })->fetchall_list;
if (keys %related_ids) {
$cat_db->select_options("ORDER BY $opts->{cat_sb} $opts->{cat_so}") if $opts->{cat_sb};
my $sth = $cat_db->select({ ID => [keys %related_ids] });
while (my $cat = $sth->fetchrow_hashref) {
my $url = $CFG->{build_root_url} . "/" . $cat_db->as_url($cat->{Full_Name}) . "/" . ($CFG->{build_index_include} ? $CFG->{build_index} : '');
$cat->{URL} = $url;
$cat->{RelationName} = $related_ids{$cat->{ID}};
push @{$tplvars{related_loop}}, $cat;
$tplvars{related} .= qq|<li><a href="$url">| . ($related_ids{$cat->{ID}} || $cat->{Full_Name}) . "</a></li>";
}
}
}
# Plugins can use the build_category_loop hook to change the category
# results before they are returned to the template.
$PLG->dispatch(build_category_loop => sub { } => \@cat_loop);
# Get the header and footer from file if it exists, otherwise assume it is html.
if ($tplvars{header} and $tplvars{header} =~ /^\S{1,20}$/ and -e "$CFG->{admin_root_path}/headers/$tplvars{header}") {
local (@ARGV, $/) = "$CFG->{admin_root_path}/headers/$tplvars{header}";
$tplvars{header} = <>;
}
if ($tplvars{footer} and $tplvars{footer} =~ /^\S{1,20}$/ and -e "$CFG->{admin_root_path}/footers/$tplvars{footer}") {
local (@ARGV, $/) = "$CFG->{admin_root_path}/footers/$tplvars{footer}";
$tplvars{footer} = <>;
}
# If we are spanning pages, figure out toolbars and such.
if ($CFG->{build_span_pages}) {
my $lpp = $CFG->{build_links_per_page};
my $nh = $opts->{nh};
my $url = $CFG->{build_root_url} . "/" . $clean_name;
$tplvars{next} = $tplvars{prev} = "";
if ($numlinks > ($nh * $lpp)) {
$tplvars{next} = "$url/$CFG->{build_more}" . ($nh + 1) . "$CFG->{build_extension}";
}
if ($nh == 2) {
$tplvars{prev} = "$url/" . ($CFG->{build_index_include} ? $CFG->{build_index} : '');
}
elsif ($nh > 2) {
$tplvars{prev} = "$url/$CFG->{build_more}" . ($nh - 1) . "$CFG->{build_extension}";
}
if ($tplvars{next} or $tplvars{prev}) {
$tplvars{next_span} = Links::Build::build('toolbar', { url => $url, numlinks => $numlinks, nh => $nh });
$tplvars{paging} = {
page => "$clean_name/",
page_format => 1,
num_hits => $numlinks,
max_hits => $opts->{mh},
current_page => $opts->{nh}
};
}
}
return Links::SiteHTML::display('category', \%tplvars);
}
sub fetch_widget_external_links {
my $id = shift || return;
return $DB->table('WidgetLinks')->select({ WidgetID => $id })->fetchall_hashref;
}
1;

View File

@ -0,0 +1,322 @@
# ==================================================================
# Plugins::Widgets - Auto Generated Program Module
#
# Plugins::Widgets
# Author : Bao Phan
# Version : 1.0
# Updated : Mon Mar 21 11:08:31 2016
#
# ==================================================================
#
package Plugins::Widgets;
# ==================================================================
use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/:objects/;
# Inherit from base class for debug and error methods
@Plugins::Widgets::ISA = qw(GT::Base);
# Your code begins here.
# ADMIN MENU OPTIONS
# ===================================================================
sub widgets {
# -------------------------------------------------------------------
# This subroutine will be called whenever the user clicks on 'Widgets' in the
# admin menu. Remember, you need to print your own HTTP header; to do so you
# can use:
my $args = shift || {};
print $IN->header;
Links::admin_page('widgets.html', { widgets => fetch_widgets($IN->param('page')), %$args });
}
sub assign {
my $cgi = $IN->get_hash();
my $msg;
if ($cgi->{page} and $cgi->{id} and $cgi->{pos}) {
my $widget = $DB->table('Widgets')->get($cgi->{id});
my $page = $cgi->{page};
my $tab_pgwidgets = $DB->table('PageWidgets');
my $pg_widget = $tab_pgwidgets->select({ WidgetID => $widget->{ID}, Page => $page })->fetchrow_hashref;
my ($msg, $category);
$category = $DB->table('Category')->get($page) if $page =~ /^\d+$/;
if (!$pg_widget and $cgi->{pos} =~ /^\d+$/) {
$tab_pgwidgets->insert({ WidgetID => $widget->{ID}, Page => $page, Sort_Pos => $cgi->{pos} || 0 }) or die $GT::SQL::error;
$msg = "The widget was added to page: " . ($category ? $category->{Full_Name} : $page);
}
elsif ($cgi->{pos} =~ /^\d+$/) {
$tab_pgwidgets->update({ Sort_Pos => $cgi->{pos} }, { ID => $pg_widget->{ID} });
$msg = "The widget's position was updated on page: " . ($category ? $category->{Full_Name} : $page);
}
else {
$tab_pgwidgets->delete({ ID => $pg_widget->{ID} });
$msg = "The widget was removed from: " . ($category ? $category->{Full_Name} : $page);
}
}
return widgets({ msg => $msg });
}
sub add {
my $cgi = $IN->get_hash();
my $error;
if ($cgi->{submit}) {
# automated widget
my @fields = ('ID', 'Type', 'Widget', 'Title', 'Subtitle', 'TitleStyle', 'Image', 'URL', 'Button');
if ($cgi->{Type}) {
return form('Widget and Title cannot be null') unless $cgi->{Widget} and $cgi->{Title};
if ($cgi->{Widget} eq 'category_list') {
return form('Select a category') unless $cgi->{Category};
push @fields, 'Category';
}
elsif ($cgi->{Widget} eq 'poll') {
return form('Select a forum') unless $cgi->{Forum};
push @fields, 'Forum';
}
elsif ($cgi->{Widget} =~ /^(:?feature_article|editors_pick|feature_threads)$/) {
return form('Enter Article IDs, comma separated') unless $cgi->{Articles};
push @fields, 'Articles';
}
elsif ($cgi->{Widget} eq 'newsletter') {
return form('Enter List ID') unless $cgi->{ListID};
push @fields, 'ListID';
}
elsif ($cgi->{Widget} eq 'external') {
return form('Enter widget title') unless $cgi->{Title};
}
}
my $rec;
if ($cgi->{Widget} eq 'external') {
$rec = $DB->table('Widgets')->add({
Title => $cgi->{Title},
TitleStyle => $cgi->{TitleStyle},
Widget => 'external',
Type => 1
});
return form($GT::SQL::error) unless $rec;
my $num_links = $cgi->{NumLinks} || 5;
my $tab_links = $DB->table("WidgetLinks");
for my $i (1 .. $num_links) {
next unless $cgi->{"Title-$i"} and $cgi->{"Abstract-$i"} and $cgi->{"URL-$i"} and $cgi->{"URL-$i"} =~ /^http/;
$tab_links->insert({
WidgetID => $rec,
Title => $cgi->{"Title-$i"},
Abstract => $cgi->{"Abstract-$i"},
URL => $cgi->{"URL-$i"},
});
}
}
else {
my %hash = map { $_ => $cgi->{$_} } @fields;
$rec = $DB->table('Widgets')->add(\%hash);
return form($GT::SQL::error) unless $rec;
}
if ($cgi->{page}) {
my $tab_pgwidgets = $DB->table('PageWidgets');
my $max_pos = $tab_pgwidgets->select('MAX(Sort_Pos)', { Page => $cgi->{page} })->fetchrow || 0;
$tab_pgwidgets->insert({ WidgetID => $rec, Page => $cgi->{page}, Sort_Pos => $max_pos + 1 });
}
return widgets({ success => "The widget was added" });
}
form();
}
sub modify {
my $cgi = $IN->get_hash();
my $widget = $DB->table('Widgets')->get($cgi->{ID});
return form("Widget not found") unless $widget;
if ($cgi->{submit}) {
# automated widget
my @fields = ('ID', 'Type', 'Widget', 'Title', 'Subtitle', 'TitleStyle', 'Image', 'URL', 'Button');
if ($cgi->{Type}) {
return form('Widget and Title cannot be null') unless $cgi->{Widget} and $cgi->{Title};
if ($cgi->{Widget} eq 'category_list') {
return form('Select a category') unless $cgi->{Category};
push @fields, 'Category';
}
elsif ($cgi->{Widget} eq 'poll') {
return form('Select a forum') unless $cgi->{Forum};
push @fields, 'Forum';
}
elsif ($cgi->{Widget} =~ /^(:?feature_article|editors_pick|feature_threads)$/) {
return form('Enter Article IDs, comma separated') unless $cgi->{Articles};
push @fields, 'Articles';
}
elsif ($cgi->{Widget} eq 'newsletter') {
return form('Enter List ID') unless $cgi->{ListID};
push @fields, 'ListID';
}
elsif ($cgi->{Widget} eq 'external') {
return form('Enter widget title') unless $cgi->{Title};
}
}
my %hash = map { $_ => $cgi->{$_} } @fields;
if ($cgi->{Widget} eq 'external') {
$DB->table('Widgets')->update({
Title => $cgi->{Title},
TitleStyle => $cgi->{TitleStyle},
}, { ID => $cgi->{ID} });
my $num_links = $cgi->{NumLinks} || 5;
my $tab_links = $DB->table("WidgetLinks");
for my $i (1 .. $num_links) {
my $id = $cgi->{"ID-$i"};
unless ($cgi->{"Title-$i"} and $cgi->{"URL-$i"} and $cgi->{"URL-$i"} =~ /^http/) {
$tab_links->delete({ ID => $id }) if $id;
}
elsif ($id) {
$tab_links->update({
Title => $cgi->{"Title-$i"},
Abstract => $cgi->{"Abstract-$i"},
URL => $cgi->{"URL-$i"},
}, { ID => $id });
}
else {
$tab_links->insert({
WidgetID => $cgi->{ID},
Title => $cgi->{"Title-$i"},
Abstract => $cgi->{"Abstract-$i"},
URL => $cgi->{"URL-$i"},
});
}
}
}
else {
my $rec = $DB->table('Widgets')->modify(\%hash);
}
return widgets({ success => "The widget was updated" });
}
else {
$IN->param($_, $widget->{$_}) for keys %$widget;
if ($widget->{Widget} eq 'external') {
my $links = $DB->table('WidgetLinks')->select({ WidgetID => $widget->{ID} })->fetchall_hashref;
my $i = 1;
foreach my $l (@$links) {
$IN->param("$_-$i", $l->{$_}) foreach (qw/ID Title Abstract URL/);
$i++;
}
}
return form();
}
}
sub retrieve_ntag {
my ($name, $index) = @_;
return unless $name and $index;
my $vars = GT::Template->vars;
return $vars->{"$name-$index"};
}
sub delete {
my $tab = $DB->table('Widgets');
my $widget = $tab->get($IN->param('ID'));
return widgets({ error => "Widget not found" }) unless $widget;
$tab->delete({ ID => $widget->{ID} });
$DB->table('PageWidgets')->delete({ WidgetID => $widget->{ID} });
$DB->table('WidgetLinks')->delete({ WidgetID => $widget->{ID} });
widgets({ success => "The widget was deleted" });
}
sub form {
print $IN->header;
my $widget = $IN->param('Widget') || '';
Links::admin_page($widget eq 'external' ? 'widgetlink_add.html' : 'widget_add.html', { error => shift });
}
sub fetch_widgets {
my $page = shift;
my $tab = $DB->table('Widgets');
my $tab_pgwidgets = $DB->table('PageWidgets');
my $tab_category = $DB->table('Category');
$tab->select_options('ORDER BY Title');
my $widgets = $tab->select()->fetchall_hashref;
my (%selected, %widgets);
if ($page) {
%selected = map { $_->{WidgetID} => $_->{Sort_Pos} } @{$tab_pgwidgets->select({ Page => $page })->fetchall_hashref};
}
my (@selected, @noselected);
foreach my $w (@$widgets) {
if ($w->{Image}) {
my $fh = $tab->file_info('Image', $w->{ID});
$w->{Image_URL} = '/images/widgets/' . $fh->File_RelativeURL;
}
$w->{pages} = $tab_pgwidgets->select({ WidgetID => $w->{ID} })->fetchall_hashref;
if ($selected{$w->{ID}}) {
$w->{selected} = $selected{$w->{ID}};
push @selected, $w;
}
else {
push @noselected, $w;
}
}
@selected = @{qsort(\@selected, 'selected', 'asc')} if scalar @selected;
return { selected => \@selected, available => \@noselected };
}
sub fetch_categories {
my $tab = $DB->table('Category');
$tab->select_options('ORDER BY Full_Name');
my $categories = $tab->select()->fetchall_hashref;
return $categories;
}
sub qsort {
my ($list, $sb, $so) = @_;
my $sorted;
@$sorted =
sort {
my $da = lc $a->{$sb}; #lower case
my $db = lc $b->{$sb};
my $res;
if ($sb eq 'selected') {
$res = $db <=> $da;
}
else {
$res = $db cmp $da;
}
if ($res == 0 and $sb ne 'name') {
lc $b->{name} cmp lc $a->{name};
}
else {
$res;
}
} @$list;
($so) and @$sorted = reverse @$sorted;
return $sorted;
}
1;

View File

@ -0,0 +1,470 @@
{
'Auth_Facebook' => {
'hooks' => [],
'meta' => {
'author' => 'Virginia Lo',
'description' => '',
'license' => 'Other',
'prog_ver' => '3.2.0',
'url' => 'http://www.gossamer-threads.com',
'version' => '1.0'
},
'user' => [
[
'fb_postback_url',
'https://www.slowtwitch.com/facebook/',
'Facebook postback url',
'TEXT',
[],
[],
''
],
[
'fb_fanpageid',
'395855247207719',
'',
'TEXT',
[],
[]
],
[
'fb_appid',
'535394536545179',
'',
'TEXT',
[],
[]
],
[
'fb_secret_key',
'0468d894e46463929bacfb6c484be3ea',
'',
'TEXT',
[],
[]
]
],
'version' => '1.0'
},
'ConvertVideo' => {
'hooks' => [
[
'validate_link',
'PRE',
'Plugins::ConvertVideo::validate_link_pre',
'1'
],
[
'modify_link',
'PRE',
'Plugins::ConvertVideo::modify_link_pre',
'1'
],
[
'modify_link',
'POST',
'Plugins::ConvertVideo::modify_link_post',
'1'
],
[
'add_link',
'POST',
'Plugins::ConvertVideo::add_link_post',
'1'
],
[
'form_link',
'PRE',
'Plugins::ConvertVideo::pre_form_link',
'1'
],
[
'form_link',
'POST',
'Plugins::ConvertVideo::post_form_link',
'1'
]
],
'meta' => {
'author' => 'Gossamer Threads Inc.',
'description' => 'Convert mpeg video to flash file.',
'license' => 'Other',
'prog_ver' => '3.x',
'url' => 'http://www.gossamer-threads.com',
'version' => '1.1'
},
'user' => [
[
'video_file_field',
'File_Path',
'Field name of the video file field.',
'TEXT',
[],
[],
''
],
[
'flash_file_field',
'Flash_Path',
'Field name of the flash file field.',
'TEXT',
[],
[],
''
],
[
'image_file_field',
'Image_Path',
'Field name of the preview image file field.',
'TEXT',
[],
[],
''
],
[
'thumbnail_file_field',
'Thumbnail_Path',
'Field name of the thumbnail file field.',
'TEXT',
[],
[],
''
],
[
'video_url_field',
'URL',
'Field name of the video url field.',
'TEXT',
[],
[],
''
],
[
'flash_dimension',
'630x398',
'The size of the flash movie (e.g. 450x370)',
'TEXT',
[],
[],
''
],
[
'flash_quality',
'1',
'quality scale (1 [best] - 31 [worst])',
'TEXT',
[],
[],
''
],
[
'thumbnail_size',
'108x108',
'The size of the thumbnail.',
'TEXT',
[],
[],
''
],
[
'watermark_file',
'',
'The path to the watermark image.',
'TEXT',
[],
[],
''
],
[
'video_url',
'/videos',
'The url where you store the video files.',
'TEXT',
[],
[],
''
],
[
'flowplayer_url',
'/videos/static',
'The url path where you store the flowplayer swf and javascript files.',
'TEXT',
[],
[],
''
]
],
'version' => '1.1'
},
'HandlePage' => {
'hooks' => [
[
'handle_page',
'PRE',
'Plugins::HandlePage::pre_handle_page',
'1'
]
],
'meta' => {
'author' => 'Gossamer Threads Inc. (Virginia Lo)',
'description' => '',
'license' => 'Other',
'prog_ver' => '3.3.0',
'url' => 'http://www.gossamer-threads.com',
'version' => '1.0'
},
'version' => '1.0'
},
'MostPopular' => {
'hooks' => [
[
'jump_link',
'PRE',
'Plugins::MostPopular::jump_link',
'1'
]
],
'meta' => {
'author' => 'Virginia Lo',
'description' => '',
'license' => 'Other',
'prog_ver' => '3.2.0',
'url' => 'http://www.gossamer-threads.com',
'version' => '1.0'
},
'user' => [
[
'last_x_days',
'14',
'most popular articles over the course of the last x days. ',
'TEXT',
[],
[],
''
]
],
'version' => '1.0'
},
'OverrideModDate' => {
'hooks' => [
[
'handle_modify',
'PRE',
'Plugins::OverrideModDate::pre_handle',
'1'
],
[
'user_add_link',
'POST',
'Plugins::OverrideModDate::post_add_link',
'1'
],
[
'modify_link',
'POST',
'Plugins::OverrideModDate::post_modify_link',
'1'
]
],
'meta' => {
'author' => 'Gossamer Threads Inc.',
'description' => 'Don\'t auto set the Add_Date and Mod_Date if a user wants to modify it. ',
'license' => 'Other',
'prog_ver' => '3.2.0',
'url' => 'http://www.gossamer-threads.com',
'version' => '1.0'
},
'version' => '1.0'
},
'SlideShow' => {
'hooks' => [
[
'add_link',
'PRE',
'Plugins::SlideShow::add_link',
'1'
],
[
'modify_link',
'PRE',
'Plugins::SlideShow::modify_link',
'1'
],
[
'user_modify_link',
'PRE',
'Plugins::SlideShow::check_input',
'1'
]
],
'menu' => [
[
'Help',
'admin.cgi?do=help&topic=SlideShow/help.html" target="_blank',
'1'
],
[
'Field Management',
'admin.cgi?do=plugin&plugin=SlideShow&func=field_management',
'1'
],
[
'Edit',
'admin.cgi?do=page&page=plugin_manager.html&plugin_man_do=edit_installed&plugin_name=SlideShow',
'1'
],
[
'Resize',
'nph-imageresize.cgi',
'1'
]
],
'meta' => {
'author' => 'Gossamer Threads Inc.',
'description' => 'This uses the SlideShow libraries and packages to allow you to run a photo gallery. This plugin automatically creates thumbnails of uploaded pictures and allows you to view them in a special frame.',
'license' => 'Commercial',
'prog_ver' => '2.1.1',
'url' => 'http://www.gossamer-threads.com/',
'version' => '1.20070309'
},
'user' => [
[
'max_upload_constraints',
'2000x2000',
'Maximum size allowed for the uploaded image.'
],
[
'max_upload_size',
'1000000',
'Maximum size in bytes for the uploaded image.'
],
[
'link_type_1',
'article',
'Link type for image width and height constraint.'
],
[
'thumbnail_constraints_1',
'100x100',
'Maximum width and height for thumbnail for link_type_1.'
],
[
'medium_constraints_1',
'300x300',
'Maximum width and height for medium sized image for link_type_1.'
],
[
'large_constraints_1',
'crop470x260',
'Maximum width and height for large image for link_type_1.'
],
[
'largest_constraints_1',
'620x620',
'Maximum width and height for largest image for link_type_1.'
],
[
'link_type_2',
'photo',
'Link type for image width and height constraint.'
],
[
'thumbnail_constraints_2',
'crop107x80',
'Maximum width and height for thumbnail for link_type_2.'
],
[
'medium_constraints_2',
'crop300x166',
'Maximum width and height for medium sized image for link_type_2.'
],
[
'large_constraints_2',
'crop470x260',
'Maximum width and height for large image for link_type_2.'
],
[
'largest_constraints_2',
'620x620',
'Maximum width and height for largest image for link_type_2.'
],
[
'image_quality',
'100',
'Used for JPGs and other lossy formats. Enter the percentage quality desired.'
],
[
'watermark_path',
'',
'Path to the watermark file. Should be a small black and white image.'
],
[
'image_cols',
'Image1,Image2,Image3,Image4,Image5,Image6,Image7,Image8,Image9,Image10,Image11,Image12,Image13,Image14,Image15,Image16,Image17,Image18,Image19,Image20',
'Name of image columns, separate with commas'
],
[
'seq_image_cols',
'Image1_medium,Image2_medium,Image3_medium,Image4_medium,Image5_medium,Image6_medium,Image7_medium,Image8_medium,Image9_medium,Image10_medium,Image11_medium,Image12_medium,Image13_medium,Image14_medium,Image15_medium,Image16_medium,Image17_medium,Image18_medium,Image19_medium,Image20_medium',
'For the next/previous pager on the showpicture.cgi. The list of columns that can be paged through.'
],
[
'temp_dir',
'/var/home/slowtwitch/slowtwitch.com/cgi-bin/articles/admin/tmp',
'Temporary directory for image work'
],
[
'image_url_path',
'/articles/images',
'URL to the uploaded images. This is the http:// prefixed URL to the directory that will receive all your images.'
]
],
'version' => '1.20100817'
},
'UI' => {
'hooks' => [
[
'build_category',
'PRE',
'Plugins::UI::build_category',
'1'
]
],
'meta' => {
'author' => 'Bao Phan',
'description' => '',
'license' => 'Freeware',
'prog_ver' => '3.3.0',
'url' => '',
'version' => '1.0'
},
'user' => [
[
'merge_categories',
'4',
'Category IDs to apply the merging option'
]
],
'version' => '1.0'
},
'Widgets' => {
'menu' => [
[
'Widgets',
'admin.cgi?do=plugin&plugin=Widgets&func=widgets',
'1'
]
],
'meta' => {
'author' => 'Bao Phan',
'description' => '',
'license' => 'Freeware',
'prog_ver' => '3.3.0',
'url' => 'http://gt.net',
'version' => '1.0'
},
'version' => '1.0'
}
};
# vim:syn=perl:ts=4:noet