Андрей (andy) wrote in changelog,
Андрей
andy
changelog

[ljcom] r9920: LJINT-362 (Comments for side projects)

Committer: ailyin
LJINT-362 (Comments for side projects)
U   trunk/cgi-bin/LJ/PartnerSite.pm
U   trunk/htdocs/identity/facebook-interstitial.bml
U   trunk/htdocs/identity/twitter-interstitial.bml
Modified: trunk/cgi-bin/LJ/PartnerSite.pm
===================================================================
--- trunk/cgi-bin/LJ/PartnerSite.pm	2011-01-18 10:07:48 UTC (rev 9919)
+++ trunk/cgi-bin/LJ/PartnerSite.pm	2011-01-18 10:45:24 UTC (rev 9920)
@@ -1,3 +1,103 @@
+=head1 NAME
+
+LJ::PartnerSite - core module for manipulating data in the journals
+bound to partner sites like kommersant.ru
+
+=head1 INTRODUCTION
+
+This module is the core module of the subsystem that allows external
+sites to use LJ to enable commenting on their articles. We consider that
+each site has a set of items ('articles') that can be commented on, and
+each of these articles has a unique identifier ('docid').
+
+There is a database table in the global cluster that stores the mapping
+from docids to the entries in the partner's journal on LJ. These entries
+are created automatically once a user tries to comment on an article.
+
+The system is exposed to the outside world by the two pages as follows:
+
+=over 2
+
+=item *
+
+comments.bml (htdocs/tools/endpoints/comments.bml): returns a JSON or a JSONP
+string with information about comments to the selected article.
+
+=item *
+
+logcom.bml (htdocs/gadgets/logcom.bml, "log in and comment"): displays a
+form that allows a user to log in and comment on the selected article.
+
+=back
+
+The system also includes several hacks inside LJ::Comment (for formatting
+comment notifications), htdocs/talkpost_do.bml (for handling errors
+differently), and interstitials in htdocs/identity.
+
+The DB table is called 'external_sites_articles_map', and it has the following
+fields:
+
+=over 2
+
+=item *
+
+partnerid
+
+=item *
+
+docid
+
+=item *
+
+docid_hash
+
+=item *
+
+jitemid
+
+=back
+
+The memcache keys of 'extarticlesmap_jitemid:$partnerid:$docid' and
+'extarticlesmap_docid:$partnerid:$jitemid' are also used to cache the
+information from this table.
+
+=head1 SYNOPSIS
+
+ my $partner = LJ::PartnerSite->find_by_api_key('api key')
+            || LJ::PartnerSite->find_by_journal_username('kommersant_test');
+ 
+ my $entry = $partner->find_entry_by_docid( 1, { 'nocreate' => 1 } );
+    $entry = $partner->find_entry_by_docid(1);
+ # $entry isa 'LJ::Entry'
+ 
+ # first parameter in the following call is docid:
+ my $link  = $partner->article_link( 1, { 'replyto' => 12345,
+                                          'view' => 12345, } );
+ 
+ # or you can pass an entry instead:
+    $link  = $partner->article_link_from_entry($entry, { 'replyto' => 12345,
+                                                         'view' => 12345, } );
+ 
+ my $docid = $partner->docid_from_entry($entry);
+ 
+ my $html  = $partner->domain_check_js({ 'mode' => 'logcom' });
+ 
+ my $js    = $partner->domain_check_js({
+     'mode' => 'jsonp',
+     'code' => 'alert("everything's ok");',
+ });
+ 
+ $partner->request_logcom_resources;
+ 
+ my $info = $partner->get_comments_info($docid, {
+     'thread' => 12345 || undef,
+     'view'   => 12345 || undef,
+     'page'   => 12345 || undef,
+     'remote' => LJ::get_remote(),
+ });
+
+=cut
+
 package LJ::PartnerSite;
 use strict;
 use warnings;
@@ -9,12 +109,115 @@
 
 use base qw( Class::Accessor );
 
+=head1 METHODS
+
+=head2 Fields and Accessorts
+
+=over 2
+
+=item *
+
+id: unique numeric identifier for the partner
+
+=item *
+
+name: the user-facing name of the partner
+
+=item *
+
+journal_username: the journal that is bound to the partner, username
+
+=item *
+
+journalid: the userid of the same journal
+
+=item *
+
+journal: the LJ::User object of the same journal
+
+=item *
+
+api_key: the unique API key identifying the partner
+
+=item *
+
+domain: the domain of the partner's site
+
+=item *
+
+link_pattern: a format to use when construcing article URLs from docids;
+[[docid]] gets replaced with the actual docid.
+
+=item *
+
+custom_css_url: the URL of the partner-provided CSS file to load in the iframe
+on the partner's site, if necessary
+
+=item *
+
+xdreceiver_url: the URL of a page on the partner's site, to provide a
+cross-domain communication channel
+
+=item *
+
+rate_limits: the rate limit for the calls to this partner's callbacks; the
+value is passed to LJ::RateLimit::check unchanged.
+
+=item *
+
+encoding: the encoding to reencode the JSON returned to this partner to.
+
+=item *
+
+mapping_locked: do not add any new entries in case we get to work with
+a docid we've never seen before. this is added as a migration option.
+
+=item *
+
+disabled: disable this partner; when this is true, all calls to
+find_entry_by_docid return undef
+
+=back
+
+=cut
+
 __PACKAGE__->mk_accessors qw( id name journal_username journalid journal
                               api_key domain link_pattern custom_css_url
-                              xdreceiver_url rate_limits encoding );
+                              xdreceiver_url rate_limits encoding
+                              mapping_locked disabled );
 
 ### CLASS METHODS ###
 
+=head2 Constructors and searching
+
+=over 2
+
+=item *
+
+LJ::PartnerSite->new(%params): bless %params into an object; this function
+actually computes journal and journalid based on journal_username, so
+you don't need to pass these two.
+
+=item *
+
+LJ::PartnerSite->find_by_id(1): return an instance with the specified
+identifier, or undef.
+
+=item *
+
+LJ::PartnerSite->find_by_api_key('api key');
+
+=item *
+
+LJ::PartnerSite->find_by_journal_username('kommersant_test');
+
+=back
+
+Note that the find_* methods actually caches the entire set of instances
+in the process memory for performance.
+
+=cut
+
 my %by_id_map;
 
 sub new {
@@ -76,12 +279,30 @@
     return Digest::MD5::md5_base64($value);
 }
 
+=head2 Various instance methods
+
+=over 2
+
+=item *
+
+$partner->find_entry_by_docid( $docid, { %opts } ): return an entry
+corresponding to this docid.
+
+Supported options: nocreate (boolean) restricts this function from
+creating a new entry.
+
+=cut
+
 sub find_entry_by_docid {
     my ( $self, $docid, $opts ) = @_;
 
+    return if $self->disabled;
+
     $docid ||= '';
     $opts ||= {};
 
+    $opts->{'nocreate'} = 1 if $self->mapping_locked;
+
     my $memc_key = 'extarticlesmap_jitemid:' . $self->id . ':' . $docid;
 
     my $jitemid = LJ::MemCache::get($memc_key);
@@ -164,6 +385,15 @@
     return LJ::Entry->new( $self->journal, 'jitemid' => $jitemid );
 }
 
+=item *
+
+$partner->article_link( $docid, { %extend } ): format the link
+to the article corresponding to the given docid. The second
+parameter is an optional hashref containing variables that are
+added to the query string of the resulting address.
+
+=cut
+
 sub article_link {
     my ( $self, $docid, $extend ) = @_;
 
@@ -179,6 +409,13 @@
     return $uri->as_string;
 }
 
+=item *
+
+$partner->docid_from_entry($entry): return the docid of the article
+corresponding to the given entry.
+
+=cut
+
 sub docid_from_entry {
     my ( $self, $entry ) = @_;
 
@@ -206,6 +443,13 @@
     return $docid;
 }
 
+=item *
+
+$partner->article_link_from_entry( $entry, $extend ): equivalent to
+calling $partner->docid_from entry and then $partner->article_link.
+
+=cut
+
 sub article_link_from_entry {
     my ( $self, $entry, $extend ) = @_;
 
@@ -213,6 +457,22 @@
     return $self->article_link( $docid, $extend );
 }
 
+=item *
+
+$partner->domain_check_js({ %opts }): return a blob of code that
+checks the domain it's executed on, as a security measure.
+
+Supported options:
+
+mode ('logcom' or 'jsonp'): 'logcom' returns HTML containing JS, and 'jsonp'
+returns JS that calls the code passed as a different parameter if the
+check succeeds.
+
+code: only if mode eq 'jsonp', the code that should be ran after the check
+succeeds.
+
+=cut
+
 sub domain_check_js {
     my ($self, $opts) = @_;
 
@@ -271,6 +531,13 @@
     }
 }
 
+=item *
+
+$partner->request_logcom_resources: call need_res and include_raw necessary
+for the page of logcom.bml
+
+=cut
+
 sub request_logcom_resources {
     my ($self) = @_;
 
@@ -383,6 +650,141 @@
     return @ret;
 }
 
+=item *
+
+$partner->get_comments_info( $docid, { %opts } ): return information about
+comments to the selected article.
+
+Supported options: thread, view, page, remote.
+
+Return value is a hashref with the fields as follows:
+
+=over 4
+
+=item *
+
+comments
+
+=item *
+
+pages
+
+=item *
+
+page
+
+=item *
+
+journal
+
+=item *
+
+auth_token
+
+=back
+
+comments is a list, and every item of this list is a hashref with the fields
+as follows:
+
+=over 4
+
+=item *
+
+comment_id
+
+=item *
+
+parent_id
+
+=item *
+
+state
+
+=item *
+
+is_open
+
+=item *
+
+timestamp
+
+=item *
+
+subject
+
+=item *
+
+text
+
+=item *
+
+username
+
+=item *
+
+display_name (missing if the poster is anonymous)
+
+=item *
+
+journal_url (missing if the poster is anonymous)
+
+=item *
+
+profile_url (missing if the poster is anonymous)
+
+=item *
+
+posters_jtype (missing if the poster is anonymous)
+
+=item *
+
+usericon (missing if the poster is anonymous)
+
+=item *
+
+can_delete
+
+=item *
+
+identity (missing if the poster is not an identity account)
+
+=back
+
+The comment identifiers there correspond to what is called 'dtalkid'
+in the other parts of LiveJournal code.
+
+The 'identity' field, if present, is also a hashref with the fields as
+follows:
+
+=over 4
+
+=item *
+
+typeid
+
+=item *
+
+shortcode
+
+=item *
+
+name
+
+=item *
+
+url
+
+=item *
+
+ljuser_display_params
+
+=back
+
+'ljuser_display_params' is whatever LJ::Identity::ljuser_display_params
+returned for this user; please refer to its documentation for details.
+
+=cut
+
 # opts: thread, view, page, remote
 sub get_comments_info {
     my ( $self, $docid, $opts ) = @_;
@@ -441,4 +843,8 @@
     };
 }
 
+=back
+
+=cut
+
 1;

Modified: trunk/htdocs/identity/facebook-interstitial.bml
===================================================================
--- trunk/htdocs/identity/facebook-interstitial.bml	2011-01-18 10:07:48 UTC (rev 9919)
+++ trunk/htdocs/identity/facebook-interstitial.bml	2011-01-18 10:45:24 UTC (rev 9920)
@@ -21,7 +21,7 @@
     my $returl  = LJ::Request->get_param('ret') || $LJ::SITEROOT;
     my $forwhat = LJ::Request->get_param('forwhat') || 'login';
 
-    my $external_site_case = ( $forwhat =~ /^external-/ );
+    my $external_site_case = ( $forwhat eq 'external' );
 
     my @errors;
 

Modified: trunk/htdocs/identity/twitter-interstitial.bml
===================================================================
--- trunk/htdocs/identity/twitter-interstitial.bml	2011-01-18 10:07:48 UTC (rev 9919)
+++ trunk/htdocs/identity/twitter-interstitial.bml	2011-01-18 10:45:24 UTC (rev 9920)
@@ -19,7 +19,7 @@
     my $returl  = LJ::Request->get_param('ret') || $LJ::SITEROOT;
     my $forwhat = LJ::Request->get_param('forwhat') || 'login';
 
-    my $external_site_case = ( $forwhat =~ /^external-/ );
+    my $external_site_case = ( $forwhat eq 'external' );
 
     my @errors;
     my $step2 = 0;
@@ -156,26 +156,6 @@
         $step2 = 1;
     };
 
-    ## LJINT-362 (Comments for side projects):
-    ## for external sites, we're actually redirecting to
-    ## the iframe page, not to $returl
-    if ( $external_site_case ) {
-        my (undef, $journalid, $ditemid, $dtalkid) = split /-/, $forwhat;
-        my $journal = LJ::load_userid($journalid);
-        my $entry = LJ::Entry->new($journal, 'ditemid' => $ditemid);
-
-        my $uri = URI->new( "$LJ::SITEROOT/gadgets/logcom.bml" );
-        $uri->query_form( $uri->query_form,
-                          'url' => $entry->prop('external_url'),
-                          'rsk' => LJ::Request->get_param('rsk') );
-
-        if ($dtalkid) {
-            $uri->query_form( $uri->query_form, 'replyto' => $dtalkid );
-        }
-
-        $returl = $uri->as_string;
-    }
-
     if (LJ::Request->did_post) {
         $handle_post->();
         return if LJ::Request->redirected;
@@ -189,25 +169,8 @@
     }
 
     my $mode = LJ::Request->get_param('mode');
-    $mode = 'full' unless defined $mode;
-
-    ## LJINT-362 (Comments for side projects):
-    ## in case an account is created on an external site, redirect them
-    ## back to a page that shows the same interstitial in an iframe
-    if ( $external_site_case && $mode ne 'compact' ) {
-        my (undef, $journalid, $ditemid, $dtalkid) = split /-/, $forwhat;
-        my $journal = LJ::load_userid($journalid);
-        my $entry = LJ::Entry->new($journal, 'ditemid' => $ditemid);
-
-        my $uri = URI->new( $entry->prop('external_url') );
-        if ($dtalkid) {
-            $uri->query_form( $uri->query_form, 'replyto' => $dtalkid );
-            $uri->fragment( 't' . $dtalkid );
-        }
-        $uri->query_form( $uri->query_form,
-                          'show' => 'twitter-interstitial/' . $forwhat );
-
-        return LJ::Request->redirect( $uri->as_string );
+    unless ( defined $mode ) {
+        $mode = $external_site_case ? 'compact' : 'full';
     }
 
     my $template_file = $mode eq 'compact' ? 'TwitterInterstitialCompact.tmpl'

Tags: andy, bml, ljcom, pm
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments