<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[10825] sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/rest-api/class-themes-auto-review.php: Api: add new controller that posts theme review results to trac from github.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="http://meta.trac.wordpress.org/changeset/10825">10825</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://meta.trac.wordpress.org/changeset/10825","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>dufresnesteven</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2021-03-17 04:42:02 +0000 (Wed, 17 Mar 2021)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Api: add new controller that posts theme review results to trac from github.</pre>

<h3>Added Paths</h3>
<ul>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginsthemedirectoryrestapiclassthemesautoreviewphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/rest-api/class-themes-auto-review.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginsthemedirectoryrestapiclassthemesautoreviewphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/rest-api/class-themes-auto-review.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/rest-api/class-themes-auto-review.php                            (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/rest-api/class-themes-auto-review.php      2021-03-17 04:42:02 UTC (rev 10825)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,173 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace WordPressdotorg\Theme_Directory\Rest_API;
+
+use WP_Error;
+use WP_REST_Controller, WP_REST_Server, WP_REST_Response;
+
+defined( 'WPINC' ) || die();
+
+/**
+ *
+ * @see WP_REST_Controller
+ */
+class Auto_Review_Controller extends WP_REST_Controller {
+
+       /**
+        * Constructor.
+        *
+        */
+       public function __construct( ) {
+               $this->namespace         = 'themes/v1';
+               $this->rest_base         = 'github';
+
+               $this->register_routes();
+       }
+
+       /**
+        * Registers the routes for the objects of the controller.
+        *
+        * @see register_rest_route()
+        */
+       public function register_routes() {
+               register_rest_route(
+                       $this->namespace,
+                       '/' . $this->rest_base . '/(?P<theme_slug>[^/]+)/(?P<ticket_id>[\d]+)/',
+                       array(
+                               'methods'             => WP_REST_Server::EDITABLE,
+                               'callback'            => array( $this, 'update_item' ),
+                               'permission_callback' => array( $this, 'update_item_permissions_check' ),
+                       )
+               );
+       }
+
+       /**
+        * A Permission Check callback which validates the request against a WP_ORG token.
+        *
+        * @param \WP_REST_Request $request The Rest API Request.
+        * @return bool|\WP_Error True if the token exists, WP_Error upon failure.
+        */
+       function update_item_permissions_check( $request ) {
+               return $this->permission_check_api_bearer( $request, 'AUTO_REVIEW_TRAC_API_GITHUB_BEARER_TOKEN' );
+       }
+
+       /**
+        * A Permission Check callback which validates the a request against a given token.
+        *
+        * @param \WP_REST_Request $request  The Rest API Request.
+        * @param string           $constant The constant that contains the expected bearer.
+        * @return bool|\WP_Error True if the token exists, WP_Error upon failure.
+        */
+       function permission_check_api_bearer( $request, $constant = false ) {
+               $authorization_header = $request->get_header( 'authorization' );
+               $authorization_header = trim( str_ireplace( 'bearer', '', $authorization_header ) );
+
+               if (
+                       ! $authorization_header ||
+                       ! $constant ||
+                       ! defined( $constant ) ||
+                       ! hash_equals( constant( $constant ), $authorization_header )
+               ) {
+                       return new \WP_Error(
+                               'not_authorized',
+                               __( 'Sorry! You cannot do that.', 'wporg-plugins' ),
+                               array( 'status' => \WP_Http::UNAUTHORIZED )
+                       );
+               }
+
+               return true;
+       }
+
+       /**
+        * Returns whether the ticket number is for the correct theme.
+        * 
+        * @param string $keywords A string that should include the theme slug.
+        * @param string $theme_slug The theme slug.
+        * @return bool
+        */
+       public function ticket_is_for_theme( $keywords, $theme_slug ) {
+               return ! empty( $keywords ) && strpos( $keywords , $theme_slug );
+       }
+
+       /**
+        * Returns a cleaned up version of the content.
+        * 
+        * @param string $content GitHub specific language to format.
+        * @return string
+        */
+       public function get_formatted_content( $content ) {
+               $padding = '<br><br>';
+
+               // Add some space around the titles
+               $content = str_replace( "]:", "]:" . $padding, $content );
+               $content = str_replace( "[", $padding . "[", $content );
+
+               // Remove empty spaces
+               $content = trim( $content );
+               $disclaimer = "
+''The following has been generated by [https://github.com/WordPress/theme-review-action Theme Review Action], this is for informational purposes only.[[br]]''
+''Theme developers: the Meta team is testing a new tool to help you to discover and fix problems that might otherwise delay approval of your theme. Please give feedback on any errors and omissions in the test results here: https://github.com/WordPress/theme-review-action/issues''";
+               
+               $content = "
+{$disclaimer}
+-----------
+{$content}
+";
+               return $content;
+       }
+
+       /**
+        *
+        * @param WP_REST_Request $request Full details about the request.
+        *
+        * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
+        */
+       public function update_item( $request ) {
+               if ( ! class_exists( 'Trac' ) ) {
+                       require_once ABSPATH . WPINC . '/class-IXR.php';
+                       require_once ABSPATH . WPINC . '/class-wp-http-ixr-client.php';
+                       require_once __DIR__ . '/lib/class-trac.php';
+               }
+
+               $trac_instance = new \Trac( 'themetracbot', THEME_TRACBOT_PASSWORD, 'https://themes.trac.wordpress.org/login/xmlrpc' );
+               $theme_slug = $request[ 'theme_slug' ];
+               $ticket_id = $request[ 'ticket_id' ];
+
+               // Check for ticket
+               $ticket = $trac_instance->ticket_get( $ticket_id );
+
+               if( ! $ticket ){
+                       return new \WP_Error(
+                               'rest_invalid_ticket',
+                               __( 'Unable to locate ticket.', 'wporg-themes' ),
+                               array( 'status' => \WP_Http::NOT_FOUND )
+                       );
+               }
+
+               $body = $request->get_body();
+
+               if( empty( $body ) ) {
+                       return new \WP_Error(
+                               'rest_error_updating_ticket',
+                               __( 'Content was empty.', 'wporg-themes' ),
+                               array( 'status' => \WP_Http::INTERNAL_SERVER_ERROR )
+                       );
+               }
+
+               $content = $this->get_formatted_content( urldecode( $body ) );
+
+               $updated_ticket = $trac_instance->ticket_update( $ticket_id, $content, [], false );
+
+               if( ! $updated_ticket ) {
+                       return new \WP_Error(
+                               'rest_error_updating_ticket',
+                               __( 'We ran into an error updating the ticket.', 'wporg-themes' ),
+                               array( 'status' => \WP_Http::INTERNAL_SERVER_ERROR )
+                       );
+               }
+
+               return new WP_REST_Response( $body_params[ 'content' ], \WP_Http::OK );
+       }
+}
+
+new Auto_Review_Controller();
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/rest-api/class-themes-auto-review.php
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span></div>

</body>
</html>