Kipcool has submitted this change and it was merged. Change subject: Special Page Add From External API ......................................................................
Special Page Add From External API This is a special page to add data to OmegaWiki via external APIs. Currently supports the Wordnik API. Since the Wordnik API is not part of the MediaWiki software, each developer who wish to use Wordnik needs to install it themselves. Kindly read the file README.md from extensions/WikiLexicalData/external folder how to activate the Wordnik API. Patch 2. i18n lowercased some words. Change-Id: I36b6e537d8ee518a7bb2146bf09327bc2161ccf0 --- M OmegaWiki/Expression.php M OmegaWiki/OmegaWikiDatabaseAPI.php M OmegaWiki/WikiDataAPI.php M OmegaWiki/forms.php M Wikidata.hooks.php A external/README.md M i18n/lexicaldata/en.json M i18n/lexicaldata/qqq.json M includes/setup/OWSpecials.php A includes/specials/ExternalWordnik.php A includes/specials/SpecialOWAddFromExternalAPI.php A resources/omegawiki-addExtAPI.js 12 files changed, 1,464 insertions(+), 127 deletions(-) Approvals: Kipcool: Verified; Looks good to me, approved Siebrand: Looks good to me, but someone else must approve diff --git a/OmegaWiki/Expression.php b/OmegaWiki/Expression.php index 7037823..1b11c03 100644 --- a/OmegaWiki/Expression.php +++ b/OmegaWiki/Expression.php @@ -73,10 +73,15 @@ $expressionId = newObjectId( "{$dc}_expression" ); if ( isset( $options['updateId'] ) ) { - $updateId = $options['updateId']; + if ( $options['updateId'] === -1 ) { + $updateId = getUpdateTransactionId(); + } else { + $updateId = $options['updateId']; + } } else { $updateId = getUpdateTransactionId(); } + $dbw->insert( "{$dc}_expression", array( 'expression_id' => $expressionId, @@ -88,6 +93,129 @@ return $expressionId; } + /** @ core getId function + * + * @param spelling req'd str + * @param languageId opt'l int + * @param option opt'l arr + * + * @return str expression id for the languageId indicated. + * @return arr The first expressionId/languageId [array( expessionId, languageId )] when languageId is skipped. + * options: + * dc str The data set + * + * @note Though you can access this function, it is highly recommended that you + * use the static function OwDatabaseAPI::getTheExpressionId instead. + */ + public static function getId( $spelling, $languageId = null, $options = array() ) { + if ( isset( $options['dc'] ) ) { + $dc = $options['dc']; + } else { + $dc = wdGetDataSetContext(); + } + $dbr = wfGetDB( DB_SLAVE ); + + $opt = array( + 'spelling' => $spelling, + 'remove_transaction_id' => null + ); + + // assumes that languageId does not exists + $var = array( 'expression_id', 'language_id' ); + // then checks if the languageId does exists + if ( $languageId ) { + $opt['language_id'] = $languageId; + $var = 'expression_id'; + // selectField returns only one field. false if not exists. + $expression = $dbr->selectField( + $dc . '_expression', $var, $opt, __METHOD__ + ); + } else { + // selectRow returns only one array. false if not exists. + $expression = $dbr->selectRow( + $dc . '_expression', $var, $opt, __METHOD__ + ); + } + + // if expression exists, returns either an array or a string + if ( $expression ) { + return $expression; + } + return null; + + } + + /** @ core getMeaningIds function + * + * @param spelling req'd str + * @param languageId opt'l arr + * @param option opt'l arr + * + * @return arr list of defined meaning ids. + * @return arr if empty, an empty array. + * options: + * dc str The data set + * + * @note Though you can access this function, it is highly recommended that you + * use the static function OwDatabaseAPI::getTheExpressionMeaningIds instead. + */ + public static function getMeaningIds( $spelling, $languageIds = array(), $options = array() ) { + if ( isset( $options['dc'] ) ) { + $dc = $options['dc']; + } else { + $dc = wdGetDataSetContext(); + } + $dbr = wfGetDB( DB_SLAVE ); + + $opt = array( + 'spelling' => $spelling, + 'exp.remove_transaction_id' => null, + 'exp.remove_transaction_id' => null, + 'exp.expression_id = synt.expression_id' + ); + + // adjust variables based on languageId existence. + if ( $languageIds ) { + // Sanity check: in case languageId is string, convert to array. + if ( is_string( $languageIds ) ) { + $temp = array( $languageIds ); // if there is a better way to convert + $languageIds= $temp; // this, kindly refactor. thanks! + } + $var = array( 'defined_meaning_id', 'language_id' ); + } else { + $var = 'defined_meaning_id'; + } + + $queryResult = $dbr->select( + array( + 'exp' => "{$dc}_expression", + 'synt' => "{$dc}_syntrans" + ), + $var, + array( + 'spelling' => $spelling, + 'exp.remove_transaction_id' => null, + 'synt.remove_transaction_id' => null, + 'exp.expression_id = synt.expression_id' + ), __METHOD__, + 'DISTINCT' + ); + + $dmlist = array(); + + foreach ( $queryResult as $synonymRecord ) { + if ( $languageIds ) { + if ( in_array( $synonymRecord->language_id, $languageIds ) ) { + $dmlist[] = $synonymRecord->defined_meaning_id; + } + } else { + $dmlist[] = $synonymRecord->defined_meaning_id; + } + } + + return $dmlist; + } + /** * returns the total number of "Expressions" * diff --git a/OmegaWiki/OmegaWikiDatabaseAPI.php b/OmegaWiki/OmegaWikiDatabaseAPI.php index bc80c5f..88a620d 100644 --- a/OmegaWiki/OmegaWikiDatabaseAPI.php +++ b/OmegaWiki/OmegaWikiDatabaseAPI.php @@ -47,6 +47,94 @@ return $api->Expression->createId( $spelling, $languageId, $options ); } + /** @brief Returns the expressionId corresponding to $spelling and $languageId + * + * @return str The expressionId + * @return null if not exist + * @see OwDatabaseAPI::getTheExpressionId + */ + public static function getExpressionId( $spelling, $languageId, $options = array() ) { + return OwDatabaseAPI::getTheExpressionId( $spelling, $languageId, $options ); + } + + /** @brief Returns the expression->expression_id corresponding to a $spelling and + * also returns the corresponding expression->languageId (the first found in the DB) + * + * @return array array( expessionId, languageId ) + * @return null if not exist + * @see OwDatabaseAPI::getTheExpressionId + */ + public static function getExpressionIdAnyLanguage( $spelling, $options = array() ) { + return OwDatabaseAPI::getTheExpressionId( $spelling, null, $options ); + } + + /** @brief returns a list of DefinedMeaning ids + * + * @return arr list of defined meaning ids. + * @return arr if empty, an empty array. + * @see OwDatabaseAPI::getExpressionMeaningIds + */ + public static function getExpressionMeaningIds( $spelling, $options = array() ) { + return OwDatabaseAPI::getTheExpressionMeaningIds( $spelling, null, $options ); + } + + /** @brief returns a list of DefinedMeaning ids for languages contained in the array languageIds + * + * @return arr list of defined meaning ids. + * @return arr if empty, an empty array. + * @see OwDatabaseAPI::getExpressionMeaningIds + */ + public static function getExpressionMeaningIdsForLanguages( $spelling, $languageIds, $options = array() ) { + return OwDatabaseAPI::getTheExpressionMeaningIds( $spelling, $languageIds, $options ); + } + + + /** @brief the core getExpression function + * + * @param spelling req'd str + * @param languageId opt'l int + * @param option opt'l arr + * + * @return str expression id for the languageId indicated. + * @return arr The first expressionId/languageId [array( expessionId, languageId )] when languageId is skipped. + * options: + * dc str The data set + * + * @see Expressions::getId. + */ + public static function getTheExpressionId( $spelling, $languageId = null, $options = array() ) { + $api = new OwDatabaseAPI; + $dc = null; + if ( isset( $options['dc'] ) ) { + $dc = $options['dc']; + } + $api->settings( 'expression', $dc ); + return $api->Expression->getId( $spelling, $languageId, $options ); + } + + /** @brief the core getMeaningIds function + * + * @param spelling req'd str + * @param languageId opt'l arr + * @param option opt'l arr + * + * @return arr list of defined meaning ids. + * @return arr if not exists, an empty array. + * options: + * dc str The data set + * + * @see Expressions::getMeaningIds. + */ + public static function getTheExpressionMeaningIds( $spelling, $languageIds, $options ) { + $api = new OwDatabaseAPI; + $dc = null; + if ( isset( $options['dc'] ) ) { + $dc = $options['dc']; + } + $api->settings( 'expression', $dc ); + return $api->Expression->getMeaningIds( $spelling, $languageIds, $options ); + } + /*! @} group OwDbAPIeFn ends here.*/ /** @addtogroup OwDbAPIdmFn OwDatabaseAPI's Defined Meaning functions @@ -375,6 +463,27 @@ return $api->Syntrans->getSpellingWithDM( $syntransId, $options, $api->dc ); } + /** + * @param definedMeaningId req'd int The defined meaning id + * @param languageId req'd int language id + * @param spelling req'd str The Expression + * + * @return array( str spelling, int language_id, int identical_meaning ) + * @return if not exists, null + * + * @see Syntrans::getAllSynonymAndTranslation + */ + public static function getSynonyms( $definedMeaningId, $languageId, $spelling ) { + $api = new OwDatabaseAPI; + $api->settings( 'syntrans' ); + $options = array( + 'language_id' => $languageId, + 'scope' => 'syn', + 'spelling' => $spelling + ); + return $api->Syntrans->getAllSynonymAndTranslation( $definedMeaningId, $options ); + } + /*! @} group OwDbAPIsyntFn ends here.*/ /** @addtogroup OwDbAPItransactFn OwDatabaseAPI's Transactions functions @@ -481,6 +590,124 @@ $expression->assureIsBoundToDefinedMeaning( $definedMeaningId, $identicalMeaning ); } + /** @brief added checks before adding Syntrans. Useful for APIs. + * + * @return an array of result or warning. + * @todo Future implemetation. Use this function in connection with + * MediaWiki/WikiLexicalData API's owAddSyntrans.php + */ + public static function addWithNotes( $spelling, $languageId, $definedMeaningId, $identicalMeaning, $options = array() ) { + global $wgUser; + $dc = wdGetDataSetContext(); + + // set test status + if ( !isset( $options['test'] ) ) { + $options['test'] = false; + } + // check that the language_id exists + if ( !verifyLanguageId( $languageId ) ) { + return array( + 'WARNING' => 'Non existent language id (' . $languageId . ').' + ); + } + + // check that defined_meaning_id exists + if ( !verifyDefinedMeaningId( $definedMeaningId ) ) { + return array( + 'WARNING' => 'Non existent dm id (' . $definedMeaningId . ').' + ); + } + + if ( $identicalMeaning === true ) { $identicalMeaning = 1; } + if ( $identicalMeaning === false ) { $identicalMeaning = 0; } + if ( $identicalMeaning === 1 ) { + $identicalMeaningStr = "true"; + if ( $options['ver'] == '1' ) { $identicalMeaning = "true"; } + } + else { + $identicalMeaningStr = "false"; + $identicalMeaning = 0; + if ( $options['ver'] == '1' ) { $identicalMeaning = "false"; } + } + + if ( !isset( $options['addedBy'] ) ) { // assumed used by API + $addedBy = 'API function add_syntrans'; + } else { + $addedBy = $options['addedBy']; + } + + // first check if it exists, then create the transaction and put it in db + $expression = findExpression( $spelling, $languageId, $options ); + $concept = getDefinedMeaningSpellingForLanguage( $definedMeaningId, WLD_ENGLISH_LANG_ID ); + if ( $expression ) { + // the expression exists, check if it has this syntrans + $bound = expressionIsBoundToDefinedMeaning ( $definedMeaningId, $expression->id ); + if ( $bound == true ) { + $synonymId = getSynonymId( $definedMeaningId, $expression->id ); + $note = array ( + 'status' => 'exists', + 'in' => $concept . ' DM(' . $definedMeaningId . ')', + 'sid' => $synonymId, + 'e' => $spelling, + 'langid' => $languageId, + 'dm' => $definedMeaningId, + 'im' => $identicalMeaning + ); + if ( $options['test'] ) { + $note['note'] = 'test run only'; + } + + return $note; + } + } + + // adding the expression + $expressionId = getExpressionId( $spelling, $languageId ); + $synonymId = getSynonymId( $definedMeaningId, $expressionId ); + $note = array ( + 'status' => 'added', + 'to' => $concept . ' DM(' . $definedMeaningId . ')', + 'sid' => $synonymId, + 'e' => $spelling, + 'langid' => $languageId, + 'dm' => $definedMeaningId, + 'im' => $identicalMeaning + ); + + // safety net. + if ( !isset( $options['transacted'] ) ) { $options['transacted'] = false; }; + if ( !isset( $options['updateId'] ) ) { $options['updateId'] = -1; }; + if ( !isset( $options['tid'] ) ) { $options['tid'] = -1; }; + if ( !isset( $options['test'] ) ) { $options['test'] = false; }; + + // add note['tid'] from $options['tid'] (transaction id), if null, get value + // from $this->options['updateId']. + if ( $options['ver'] == '1.1' ) { + if ( $options['tid'] ) { + $note['tid'] = $options['tid']; + } else { + $note['tid'] = $options['updateId']; + } + } + + if ( !$options['test'] ) { + if ( !$options['transacted'] ) { + $note['transacted'] = true; // @todo when used in owAddSyntrans.php, kindly use this to switch $this->transacted to true. + $tid = startNewTransaction( $wgUser->getID(), "0.0.0.0", 'Added using ' . $addedBy, $dc ); + if ( $options['ver'] == '1.1' ) { + $note['tid'] = $tid; + } + } + OwDatabaseAPI::addSynonymOrTranslation( $spelling, $languageId, $definedMeaningId, $identicalMeaningStr, $options ); + $synonymId = getSynonymId( $definedMeaningId, $expressionId ); + $note['sidd'] = $synonymId; + } else { + $note['note'] = 'test run only'; + } + + return $note; + } + /** * @param syntransId req'd int The syntrans id * @param options opt'l arr An optional parameters @@ -530,4 +757,80 @@ return array(); } + /** @brief core get syntrans function + * + * @param definedMeaningId int req'd + * @param options int opt'l + * + * @return array( str spelling, int language_id, int identical_meaning ) + * @return if not exists, null + */ + public static function getAllSynonymAndTranslation( $definedMeaningId, $options ) { + if ( isset( $options['dc'] ) ) { + $dc = $options['dc']; + } else { + $dc = wdGetDataSetContext(); + } + $dbr = wfGetDB( DB_SLAVE ); + + $opt = array( + 'defined_meaning_id' => $definedMeaningId, + 'st.expression_id = e.expression_id', + 'st.remove_transaction_id' => null + ); + + if( isset( $options['language_id'] ) ) { + $languageId = $options['language_id']; + } + + if( isset( $options['spelling'] ) ) { + $spelling = $options['spelling']; + } + + if( isset( $options['scope'] ) ) { + switch( $options['scope'] ) { + case 'syn': + $opt['language_id'] = $languageId; + $opt[] = 'spelling not in (' . "'" . $spelling . "'" . ')'; + break; + } + } + + $result = $dbr->select( + array( + 'e' => "{$dc}_expression", + 'st' => "{$dc}_syntrans" + ), + array( + 'spelling', + 'language_id', + 'identical_meaning', + 'syntrans_sid' + ), + $opt, __METHOD__, + array( + 'ORDER BY' => array ( + 'identical_meaning DESC', + 'language_id', + 'spelling' + ) + ) + ); + + $syntrans = array(); + foreach ( $result as $row ) { + $syntrans[] = array( + 0 => $row->spelling, + 1 => $row->language_id, + 2 => $row->identical_meaning, + 3 => $row->syntrans_sid + ); + } + + if ( $syntrans ) { + return $syntrans; + } + return null; + } + } diff --git a/OmegaWiki/WikiDataAPI.php b/OmegaWiki/WikiDataAPI.php index 638ea99..8054744 100644 --- a/OmegaWiki/WikiDataAPI.php +++ b/OmegaWiki/WikiDataAPI.php @@ -73,53 +73,16 @@ return ""; } -/** - * Returns the expressionId corresponding to $spelling and $languageId - * @return null if not exist +/** @todo for deprecation. Use OwDatabaseAPI::getExpressionId */ function getExpressionId( $spelling, $languageId ) { - $dc = wdGetDataSetContext(); - $dbr = wfGetDB( DB_SLAVE ); - - $expressionId = $dbr->selectField( - "{$dc}_expression", - 'expression_id', - array( - 'spelling' => $spelling, - 'language_id' => $languageId, - 'remove_transaction_id' => null - ), __METHOD__ - ); - - if ( $expressionId ) { - return $expressionId; - } - return null; + return OwDatabaseAPI::getExpressionId( $spelling, $languageId ); } -/** - * Returns the expression->expression_id corresponding to a $spelling and - * also returns the corresponding expression->languageId (the first found in the DB) - * returns null if not exist +/** @todo for deprecation. Use OwDatabaseAPI::getExpressionIdAnyLanguage */ function getExpressionIdAnyLanguage( $spelling ) { - $dc = wdGetDataSetContext(); - $dbr = wfGetDB( DB_SLAVE ); - - // selectRow returns only one. false if not exists. - $expression = $dbr->selectRow( - "{$dc}_expression", - array( 'expression_id', 'language_id' ), - array( - 'spelling' => $spelling, - 'remove_transaction_id' => null - ), __METHOD__ - ); - - if ( $expression ) { - return $expression; - } - return null; + return OwDatabaseAPI::getExpressionIdAnyLanguage( $spelling ); } function getRemovedExpressionId( $spelling, $languageId ) { @@ -236,17 +199,23 @@ } /** - * returns true if a spelling exists in the - * expression table of the database + * @return boolean if a spelling exists in the expression table of the database */ -function existSpelling( $spelling ) { +function existSpelling( $spelling, $languageId = 0 ) { $dc = wdGetDataSetContext(); $dbr = wfGetDB( DB_SLAVE ); + + $cond = array( 'spelling' => $spelling, 'remove_transaction_id' => null ); + + if ( $languageId > 0 ) { + $cond['language_id'] = $languageId; + } + $expressionId = $dbr->selectField( "{$dc}_expression", 'expression_id', - array( 'spelling' => $spelling, 'remove_transaction_id' => null ), + $cond, __METHOD__ ); @@ -2130,64 +2099,16 @@ return 0; } +/** @todo for deprecation. use OwDatabaseAPI::getExpressionMeaningIds instead. + */ function getExpressionMeaningIds( $spelling, $dc = null ) { - if ( is_null( $dc ) ) { - $dc = wdGetDataSetContext(); - } - $dbr = wfGetDB( DB_SLAVE ); - - $queryResult = $dbr->select( - array( - 'exp' => "{$dc}_expression", - 'synt' => "{$dc}_syntrans" - ), - 'defined_meaning_id', - array( - 'spelling' => $spelling, - 'exp.remove_transaction_id' => null, - 'synt.remove_transaction_id' => null, - 'exp.expression_id = synt.expression_id' - ), __METHOD__ - ); - - $dmlist = array(); - - foreach ( $queryResult as $synonymRecord ) { - $dmlist[] = $synonymRecord->defined_meaning_id; - } - - return $dmlist; + return OwDatabaseAPI::getExpressionMeaningIds( $spelling, array( 'dc' => $dc ) ); } +/** @todo for deprecation. use OwDatabaseAPI::getExpressionMeaningIdsForLanguages instead. + */ function getExpressionMeaningIdsForLanguages( $spelling, $languageIds, $dc = null ) { - if ( is_null( $dc ) ) { - $dc = wdGetDataSetContext(); - } - $dbr = wfGetDB( DB_SLAVE ); - - $queryResult = $dbr->select( - array( - 'exp' => "{$dc}_expression", - 'synt' => "{$dc}_syntrans" - ), - array( 'defined_meaning_id', 'language_id' ), - array( - 'spelling' => $spelling, - 'exp.expression_id = synt.expression_id', - 'synt.remove_transaction_id' => null, - 'exp.remove_transaction_id' => null - ), __METHOD__, - 'DISTINCT' - ); - - $dmlist = array(); - - foreach( $queryResult as $synonymRecord ) { - if ( in_array( $synonymRecord->language_id, $languageIds ) ) { - $dmlist[] = $synonymRecord->defined_meaning_id; - } - } - return $dmlist; + return OwDatabaseAPI::getExpressionMeaningIdsForLanguages( $spelling, $languageIds, array( 'dc' => $dc ) ); } /** Get Defined Meaning Ids from Expression Id diff --git a/OmegaWiki/forms.php b/OmegaWiki/forms.php index ae6374d..029a99d 100644 --- a/OmegaWiki/forms.php +++ b/OmegaWiki/forms.php @@ -13,9 +13,9 @@ '" value="' . htmlspecialchars( $value ) . '"' . $onChangeAttribute . ' style="width: 100%; padding: 0px; margin: 0px;"/>' ; - return $inputHTML ; + return $inputHTML; } - + function getTextArea( $name, $text = "", $rows = 5, $columns = 80, $disabled = false ) { if ( $disabled ) { // READONLY alone is not enough: apparently, some browsers ignore it @@ -31,7 +31,7 @@ } return ''; } - + function getCheckBox( $name, $isChecked, $disabled = false ) { // a disabled checkbox returns no value, as if unchecked // therefore the value of a disabled, but checked, checkbox must be sent with a hidden input @@ -69,28 +69,11 @@ } } -# $options is an array of [value => text] pairs +/** @todo for deprecration use Class OmegaWikiForms's getSelect function instead. + */ function getSelect( $name, $options, $selectedValue = "", $onChangeHandler = "" ) { - if ( $onChangeHandler != "" ) { - $onChangeAttribute = ' onchange="' . $onChangeHandler . '"'; - } else { - $onChangeAttribute = ''; - } - - $result = '<select id="' . $name . '" name="' . $name . '"' . $onChangeAttribute . '>'; - - asort( $options ); - - foreach ( $options as $value => $text ) { - if ( $value == $selectedValue ) - $selected = ' selected="selected"'; - else - $selected = ''; - - $result .= '<option value="' . $value . '"' . $selected . '>' . htmlspecialchars( $text ) . '</option>'; - } - - return $result . '</select>'; + $form = new OmegaWikiForms; + return $form->getSelect( $name, $options, $selectedValue, $onChangeHandler ); } function getFileField( $name, $onChangeHandler = "" ) { @@ -101,7 +84,6 @@ return '<input type="file" id="' . $name . '" name="' . $name . '"' . $onChangeAttribute . ' style="width: 100%; padding: 0px; margin: 0px;"/>'; } - /** * @@ -296,3 +278,137 @@ return $result; } +/** @brief Generic Forms + */ +class GenericForms { + + public function __construct() { + $this->labelTemplate = '                '; + } + + + /** + * @return HTML string for HTML tag select + * + * @param name str req'd unique identifier for this form field + * @param options arr req'd list of options, [value => text] pairs + * @param selectedValue str opt'l in case a value is present + * @param onChangeHandler str js + */ + function getSelect( $name, $options, $selectedValue = "", $onChangeHandler = "" ) { + if ( $onChangeHandler != "" ) { + $onChangeAttribute = ' onchange="' . $onChangeHandler . '"'; + } else { + $onChangeAttribute = ''; + } + + $result = '<select id="' . $name . '" name="' . $name . '"' . $onChangeAttribute . '>'; + + asort( $options ); + + foreach ( $options as $value => $text ) { + if ( $value == $selectedValue ) { + $selected = ' selected="selected"'; + } else { + $selected = ''; + } + + $result .= '<option value="' . $value . '"' . $selected . '>' . htmlspecialchars( $text ) . '</option>'; + } + + return $result . '</select>'; + } + + /** + * @return HTML string for HTML input type text + * @param name str req'd unique identifier for this form field + * @param value str opt'l input value + * @param onChangeHandler str opt'l js + * @param disabled boolean opt'l to disable editing of the field + */ + public function getTextBox( $name, $value = "", $onChangeHandler = "", $disabled = false ) { + if ( $onChangeHandler != "" ) { + $onChangeAttribute = ' onchange="' . $onChangeHandler . '"'; + } else { + $onChangeAttribute = ''; + } + + $disableText = $disabled ? 'disabled="disabled" ' : ''; + $inputHTML = '<input ' . $disableText . 'type="text" id="' . $name . '" name="' . $name . + '" value="' . htmlspecialchars( $value ) . '"' . $onChangeAttribute . + ' style="width: 100%; padding: 0px; margin: 0px;"/>'; + + return $inputHTML; + } + +} + +/** @brief OmegaWiki extension to the generic forms + */ +class OmegaWikiForms extends GenericForms { + + public function __construct() { + parent::__construct(); + } + + /** + * + * @return HTML for an autocompleted form field. + * + * @param name str unique identifier for this form field + * @param query str type of query to run + * @param parameters arr span options (parameters and values ) + * @param value int Default value + * @param label str How default value will be shown + * @param displayLabelColumns arr Override column titles + * @param DataSet str Override standard dataset + * + */ + function getSuggest( $name, $query, $parameters = array(), $value = 0, $label = '', $displayLabelColumns = array( 0 ), DataSet $dc = null ) { + global $wgScriptPath; + + if ( is_null( $dc ) ) { + $dc = wdGetDataSetContext(); + } + if ( $label == "" ) { + $label = $this->labelTemplate; + } + + $result = Html::openElement('span', array( 'class' => 'suggest' ) ); + + // the input that will contain the value selected with suggest.js + $inputOptions = array( + 'id' => $name, + 'name' => $name, + 'value' => $value, + 'type' => 'hidden' + ); + $result .= Html::element('input', $inputOptions); + + $spanOptions = array( + 'id' => $name . '-suggest-link', + 'name' => $name . '-suggest-link', + 'class' => 'suggest-link', + 'title' => wfMessage( "ow_SuggestHint" )->text(), + 'query' => $query, + 'offset' => 0, + 'label-columns' => implode( ', ', $displayLabelColumns ), + 'dataset' => $dc + ); + + foreach( $parameters as $parameter => $parameterValue ) { + // parameters like level, definedMeaningId, annotationAttributeId, syntransId + $spanOptions[$parameter] = $parameterValue; + } + + $result .= Html::rawElement( 'span', $spanOptions, $label ); + + $result .= Html::closeElement( 'span' ); + + // The table that then allows to select from a dropdown list + // is generated with javascript (cf. suggest.js) + + return $result; + } + +} diff --git a/Wikidata.hooks.php b/Wikidata.hooks.php index 4579937..998cca4 100644 --- a/Wikidata.hooks.php +++ b/Wikidata.hooks.php @@ -26,6 +26,14 @@ $out->setPageTitle( mb_substr( $out->getPageTitle(), mb_strlen( $namespaceText ) + 1 ) ); } } + + // SpecialPage Add from External API + if ( + $skin->getTitle()->mNamespace === -1 and + $skin->getTitle()->mTextform === 'Ow addFromExtAPI' + ) { + $out->addModules( 'ext.OwAddFromExtAPI.js' ); + } return true; } diff --git a/external/README.md b/external/README.md new file mode 100644 index 0000000..c515431 --- /dev/null +++ b/external/README.md @@ -0,0 +1,26 @@ +# Installing External APIs + +This directory will be used to add external APIs. + +## APIs that are supported by WikiLexicalData + +### Wordnik + +Currently tested with Wordnik.com v4 API. + +#### Basic Setup + +Place the `wordnik` folder that you downloaded in this directory +where it can be accessed by WikiLexicaldata. + +Obtain an API key from Wordnik. + +Then create a PHP file under this directory named wordnikConfig.php and +with the following code: + + <?php + global $myWordnikAPIKey; + $myWordnikAPIKey = '<PLACE_YOUR_WORDNIK_API_KEY_HERE>'; + +Replace <PLACE_YOUR_WORDNIK_API_KEY_HERE> with the API key you have received +from Wordnik. diff --git a/i18n/lexicaldata/en.json b/i18n/lexicaldata/en.json index a775ee9..3ae0901 100644 --- a/i18n/lexicaldata/en.json +++ b/i18n/lexicaldata/en.json @@ -216,5 +216,8 @@ "prefs-omegawiki": "OmegaWiki", "prefs-ow-lang": "Languages", "ow_pref_lang_switch": "Show only the selected languages", - "ow_pref_lang_select": "Languages to display:" + "ow_pref_lang_select": "Languages to display:", + "ow_addFromExtAPI": "Add data from external APIs", + "ow_addFromExtAPI_title" : "Add data from API", + "ow_api_source" : "External API source:" } diff --git a/i18n/lexicaldata/qqq.json b/i18n/lexicaldata/qqq.json index fe1cc1b..7eec342 100644 --- a/i18n/lexicaldata/qqq.json +++ b/i18n/lexicaldata/qqq.json @@ -147,5 +147,8 @@ "prefs-omegawiki": "{{optional}}", "prefs-ow-lang": "A header in the user preferences where the user can configure languages.\n{{Identical|Language}}", "ow_pref_lang_switch": "A checkbox in the user preferences. If checked, it allows the user to select which languages should be displayed. If unchecked, all languages are displayed.", - "ow_pref_lang_select": "Next to this text is shown a list of languages, each with a checkbox, to select the languages to display or hide in OmegaWiki" + "ow_pref_lang_select": "Next to this text is shown a list of languages, each with a checkbox, to select the languages to display or hide in OmegaWiki", + "ow_addFromExtAPI": "Special page name for adding OmegaWiki data from External APIs", + "ow_addFromExtAPI_title" : "The page title for Special page name for adding OmegaWiki data from External APIs", + "ow_api_source" : "External API source label" } diff --git a/includes/setup/OWSpecials.php b/includes/setup/OWSpecials.php index 915c63d..6b12fdc 100644 --- a/includes/setup/OWSpecials.php +++ b/includes/setup/OWSpecials.php @@ -82,6 +82,11 @@ 'author' => 'Hiong3-eng5', ); +$wgExtensionCredits['specialpage'][] = array( + 'name' => 'SpecialAddFromExternalAPI', + 'author' => 'Hiong3-eng5', +); + # Location of the SpecialMyExtension class (Tell MediaWiki to load this file) $wgAutoloadClasses['SpecialCopy'] = $dir . 'OmegaWiki/SpecialCopy.php'; $wgAutoloadClasses['SpecialSelect'] = $dir . 'OmegaWiki/SpecialSelect.php'; @@ -99,6 +104,8 @@ $wgAutoloadClasses['SpecialExportTSV'] = $wgWldSpecialsScriptPath . 'SpecialExportTSV.php'; $wgAutoloadClasses['SpecialImportTSV'] = $wgWldSpecialsScriptPath . 'SpecialImportTSV.php'; + +$wgAutoloadClasses['SpecialOWAddFromExternalAPI'] = $wgWldSpecialsScriptPath . 'SpecialOWAddFromExternalAPI.php'; // $wgAutoloadClasses['SpecialTransaction'] = $dir . 'OmegaWiki/SpecialTransaction.php'; @@ -119,6 +126,8 @@ $wgSpecialPages['exportTSV'] = 'SpecialExportTSV'; $wgSpecialPages['importTSV'] = 'SpecialImportTSV'; + +$wgSpecialPages['ow_addFromExtAPI'] = 'SpecialOWAddFromExternalAPI'; // $wgSpecialPages['Transaction'] = 'SpecialTransaction'; @@ -143,6 +152,33 @@ $wgSpecialPageGroups[ 'ow_statistics' ] = 'wiki'; $wgSpecialPageGroups[ 'ow_downloads' ] = 'wiki'; +// special page with conditional groups + +// ow_addFromExtAPI + +global $wgWldProcessExternalAPIClasses, $wgWldExtenalResourceLanguages, $wgWldScriptPath; +$wgWldProcessExternalAPIClasses = array(); +$wgWldExtenalResourceLanguages = array(); + +if ( file_exists( $wgWldScriptPath . '/external/wordnik/wordnik/Swagger.php' ) ) { + $wgAutoloadClasses['WordnikExtension' ] = $wgWldSpecialsScriptPath . 'ExternalWordnik.php'; + $wgAutoloadClasses['WordnikWiktionaryExtension' ] = $wgWldSpecialsScriptPath . 'ExternalWordnik.php'; + $wgAutoloadClasses['WordnikWordnetExtension' ] = $wgWldSpecialsScriptPath . 'ExternalWordnik.php'; + $wgWldProcessExternalAPIClasses['WordnikExtension'] = 'Wordnik'; + $wgWldProcessExternalAPIClasses['WordnikWiktionaryExtension'] = 'Wordnik Wiktionary'; + $wgWldProcessExternalAPIClasses['WordnikWordnetExtension'] = 'Wordnik Wordnet'; + $wgWldExtenalResourceLanguages[WLD_ENGLISH_LANG_ID] = 'English'; + require_once( $wgWldScriptPath . '/external/wordnikConfig.php' ); +} + +if ( $wgWldProcessExternalAPIClasses ) { + $wgSpecialPageGroups[ 'ow_addFromExtAPI' ] = 'maintenance'; + + $wgResourceModules['ext.OwAddFromExtAPI.js'] = $resourcePathArray + array( + 'scripts' => 'omegawiki-addExtAPI.js' + ); +} + # Location of an aliases file (Tell MediaWiki to load this file) //$wgExtensionMessagesFiles[ 'OWSpecialsAlias' ] = #dir . '../i18n/OWSpecials.alias.php'; diff --git a/includes/specials/ExternalWordnik.php b/includes/specials/ExternalWordnik.php new file mode 100644 index 0000000..951fa06 --- /dev/null +++ b/includes/specials/ExternalWordnik.php @@ -0,0 +1,131 @@ +<?php + +if ( !defined( 'MEDIAWIKI' ) ) die(); + +/** @brief class to access Wordnik's API + */ +class WordnikExtension extends ExternalResources { + + private $wordApi; //< object to handle Wordnik's API + + /** @note see ExternalResources::__contruct + */ + function __construct( $spTitle, $source, $sourceLanguageId, $search, $collectionId ) { + parent::__construct( $spTitle, $source, $sourceLanguageId, $search, $collectionId ); + preg_match( '/^Wordnik(.+)/', $this->source, $match ); + $this->sourceLabel = 'Wordnik ' . $match[1]; + + global $myWordnikAPIKey; + require_once( __DIR__ . '/../../external/wordnik/wordnik/Swagger.php' ); + $wgWldExtenalResourceLanguages = array( + 85 => 'English' + ); + $WordnikClient = new APIClient($myWordnikAPIKey, 'http://api.wordnik.com/v4'); + $this->wordApi = new WordApi( $WordnikClient ); + $this->sourceDictionary = 'all'; + + } + + function execute() { + // reconstruct spTitle + $this->spTitle = 'Wordnik: ' . $this->spTitle; + parent::execute(); + } + + function checkExternalDefinition() { + // $example = $this->wordApi->getTopExample('big'); + // $exampleSentence = $example->text; + $this->externalDefinition = $this->wordApi->getDefinitions( $this->search, null, $this->sourceDictionary, null, 'true' ); + $this->externalExists = true; + if ( $this->externalDefinition ) { + $this->externalExists = true; + } + } + + function setExternalDefinition() { + $this->externalLexicalData = array(); + + if ( $this->externalDefinition ) { + foreach( $this->externalDefinition as $definition ) { + if ( $definition->sourceDictionary !== 'ahd-legacy' ) { + + $this->setExternalLexicalData( $definition ); + + } + } + } + $this->externalLexicalDataJSON = json_encode( $this->externalLexicalData ); + // line below for testing purpose when without internet for expression 'pig' + // $this->getTestExternalDefinition(); + $this->wgOut->addHTML( + '<div id="ext-data">' . $this->externalLexicalDataJSON . '</div>' + ); + } + + /** Includes only definitions that are relevant. Filters out definitions + * that would be useless to the current program. + * @note currently, only related words have data that is relevant to this special page. + */ + function setExternalLexicalData( $definition ) { + $includeDefinition = $this->includeDefinition( $definition ); + + if ( $includeDefinition === true ) { + $this->externalLexicalData[] = array( + 'process' => null, + 'src' => $definition->sourceDictionary, + 'text' => $definition->text, + 'partOfSpeech' => $definition->partOfSpeech, + 'relatedWords' => $definition->relatedWords + ); + } + } + + private function includeDefinition( $definition ) { + $includeDefinition = false; + if ( $definition->relatedWords ) { + foreach( $definition->relatedWords as $rw ) { + switch ( $rw->relationshipType ) { + case 'synonym': $includeDefinition = true; break; + } + } + } + + return $includeDefinition; + } + + private function getTestExternalDefinition() { + $this->externalLexicalDataJSON = '[{"process":null,"src":"wiktionary","text":"earthenware, or an earthenware shard","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"An earthenware hot-water jar to warm a bed; a stone bed warmer","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"a pigeon.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"Any of several mammals of the genus Sus, having cloven hooves, bristles and a nose adapted for digging; especially the domesticated farm animal Sus scrofa.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A young swine, a piglet.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"The edible meat of such an animal; pork.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"Someone who overeats or eats rapidly and noisily.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A nasty or disgusting person.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A dirty or slovenly person.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A difficult problem.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A block of cast metal.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"The mold in which a block of metal is cast.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A device for cleaning or inspecting the inside of an oil or gas pipeline, or for separating different substances within the pipeline. Named for the pig-like squealing noise made by their progress.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"a person who is obese to the extent of resembling a pig (the animal)","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"to give birth.","partOfSpeech":"verb","relatedWords":[]},{"process":null,"src":"wiktionary","text":"To greedily consume (especially food).","partOfSpeech":"verb","relatedWords":[]},{"process":null,"src":"wiktionary","text":"To huddle or lie together like pigs, in one bed.","partOfSpeech":"verb","relatedWords":[]},{"process":null,"src":"gcide","text":"A piggin.","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"synonym","label2":null,"label3":null,"words":["piggin"],"gram":null,"label4":null},{"label1":null,"relationshipType":"variant","label2":null,"label3":null,"words":["pigg"],"gram":null,"label4":null}]},{"process":null,"src":"gcide","text":"The young of swine, male or female; also, any swine; a hog.","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"synonym","label2":null,"label3":null,"words":["hog"],"gram":null,"label4":null}]},{"process":null,"src":"gcide","text":"Any wild species of the genus Sus and related genera.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"gcide","text":"An oblong mass of cast iron, lead, or other metal. See Mine pig, under Mine.","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"variant","label2":null,"label3":null,"words":["mine"],"gram":null,"label4":null}]},{"process":null,"src":"gcide","text":"One who is hoggish; a greedy person.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"gcide","text":"To bring forth (pigs); to bring forth in the manner of pigs; to farrow.","partOfSpeech":"verb","relatedWords":[{"label1":null,"relationshipType":"form","label2":null,"label3":null,"words":["pigged"],"gram":"imp. & p. p.","label4":null},{"label1":null,"relationshipType":"form","label2":null,"label3":null,"words":["pigging"],"gram":"p. pr. & vb. n.","label4":null},{"label1":null,"relationshipType":"synonym","label2":null,"label3":null,"words":["farrow"],"gram":null,"label4":null},{"label1":null,"relationshipType":"form","label2":null,"label3":null,"words":["pigged"],"gram":"imp. & p. p.","label4":null},{"label1":null,"relationshipType":"form","label2":null,"label3":null,"words":["pigging"],"gram":"p. pr. & vb. n.","label4":null}]},{"process":null,"src":"gcide","text":"To huddle or lie together like pigs, in one bed.","partOfSpeech":"verb","relatedWords":[]},{"process":null,"src":"century","text":"A hog; a swine; especially, a porker, or young swine of either sex, the old male being called boar, the old female sow.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"The flesh of swine; pork.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"An oblong mass of metal that has been run while still molten into a mold excavated in sand; specifically, iron from the blast-furnace run into molds excavated in sand.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"A customary unit of weight for lead, 301 pounds.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"A very short space of time.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"To bring forth pigs; bring forth in the manner of pigs; litter.","partOfSpeech":null,"relatedWords":[]},{"process":null,"src":"century","text":"To act as pigs; live like a pig; live or huddle as pigs: sometimes with an indefinite it.","partOfSpeech":null,"relatedWords":[]},{"process":null,"src":"century","text":"An earthen vessel; any article of earthenware.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"A can for a chimney-top.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"A potsherd.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"Pig-iron collectively or any specified amount of iron pigs.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"In forestry, see rigging-sled.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wordnet","text":"domestic swine","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hyponym","label2":null,"label3":null,"words":["porker"],"gram":null,"label4":null},{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["swine"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"live like a pig, in squalor","partOfSpeech":"verb","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["live"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"give birth","partOfSpeech":"verb","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["bear","give birth","birth","have","deliver"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"a person regarded as greedy and pig-like","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["selfish person"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"eat greedily","partOfSpeech":"verb","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["eat"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"uncomplimentary terms for a policeman","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["police officer","policeman","officer"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"a crude block of metal (lead or iron) poured from a smelting furnace","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["ingot","metal bar","block of metal"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"a coarse obnoxious person","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hyponym","label2":null,"label3":null,"words":["litterbug","litter lout","slattern","trollop","slut","litterer","slovenly woman"],"gram":null,"label4":null},{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["vulgarian"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"mold consisting of a bed of sand in which pig iron is cast","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["mold","cast","mould"],"gram":null,"label4":null}]}]'; + $this->tempExternalLexicalData = json_decode( $this->externalLexicalDataJSON ); + + $this->externalLexicalData = array(); + + foreach( $this->tempExternalLexicalData as $definition ) { + if ( $definition->src !== 'ahd-legacy' ) { + + $includeDefinition = $this->includeDefinition( $definition ); + + if ( $includeDefinition ) { + $this->externalLexicalData[] = $definition; + } + + } + } + + $this->externalLexicalDataJSON = json_encode( $this->externalLexicalData ); + + } +} + +class WordnikWiktionaryExtension extends WordnikExtension { + function __construct( $spTitle, $source, $sourceLanguageId, $search, $collectionId ) { + parent::__construct( $spTitle, $source, $sourceLanguageId, $search, $collectionId ); + $this->sourceDictionary = 'wiktionary'; + } +} + +class WordnikWordnetExtension extends WordnikExtension { + function __construct( $spTitle, $source, $sourceLanguageId, $search, $collectionId ) { + parent::__construct( $spTitle, $source, $sourceLanguageId, $search, $collectionId ); + $this->sourceDictionary = 'wordnet'; + } +} diff --git a/includes/specials/SpecialOWAddFromExternalAPI.php b/includes/specials/SpecialOWAddFromExternalAPI.php new file mode 100644 index 0000000..f739063 --- /dev/null +++ b/includes/specials/SpecialOWAddFromExternalAPI.php @@ -0,0 +1,314 @@ +<?php + +if ( !defined( 'MEDIAWIKI' ) ) die(); + +require_once( __DIR__ . "/../../OmegaWiki/OmegaWikiDatabaseAPI.php" ); +/** @file + * @brief Special Page to add data from external sources via APIs + * + * This special page consist of the special page to process data and a + * web api that is used by its accompanying js script ( omegawiki-addExtAPI.js ). + * Currently only adds synonyms via an external Wordnik API. + * + * First release: September 2014. + * + * @note he: This is not as simple as I thought. So phase one will only be adding synonyms. + * + * @todo phase 2: text annotations + * + * @note he: limit SP to editwikidata-uw and exclude blocked users. Is this enough + * or too much? + */ +class SpecialOWAddFromExternalAPI extends SpecialPage { + + private $saveResult; // string Used to output JSON via this class' web API (POST). + private $saveType; // string The type to save. see save function. + + function __construct() { + global $wgWldProcessExternalAPIClasses; + if ( $wgWldProcessExternalAPIClasses ) { + parent::__construct( 'ow_addFromExtAPI' ); + } else { + parent::__construct( 'ow_addFromExtAPI', 'UnlistedSpecialPage' ); + } + } + + /** @brief This function is used as a web API by omegawiki-addExtAPI.js + * This function directs the program to the needed save function via $this->saveType. + * Afterwards, outputs a JSON string. + */ + private function save() { + + switch ( $this->saveType ) { + case 'synonym': $this->saveSynonym(); break; + break; + } + + // disable wgOut in order to output only the JSON string. + global $wgOut; + $wgOut->disable(); + echo json_encode( $this->saveResult ); + + } + + /** @brief This is the save function that handles adding Synonyms. + * + */ + private function saveSynonym() { + $definedMeaningId = array_key_exists( 'dm-id', $_POST ) ? $_POST['dm-id'] : ''; + $languageId = array_key_exists( 'lang-id', $_POST ) ? $_POST['lang-id'] : ''; + $spelling = array_key_exists( 'e', $_POST ) ? $_POST['e'] : ''; + $identicalMeaning = array_key_exists( 'im', $_POST ) ? $_POST['im'] : 1; + $transactionId = array_key_exists( 'tid', $_POST ) ? $_POST['tid'] : ''; + $transacted = array_key_exists( 'transacted', $_POST ) ? $_POST['transacted'] : false; + $source = array_key_exists( 'src', $_POST ) ? $_POST['src'] : ''; + + // @todo create checks for correctness + if ( $identicalMeaning === true ) { $identicalMeaning = 1; } + if ( $identicalMeaning === false ) { $identicalMeaning = 0; } + if ( $identicalMeaning === '' ) { $identicalMeaning = 1; } + + $options = array( + 'ver' => '1.1', + // 'test' => true, + 'dc' => 'uw', + 'transacted' => $transacted, + 'addedBy' => 'SpecialPage SpecialOWAddFromExternalAPI'//, + // 'tid', + // 'updateId' + ); + + if ( $transactionId ) { + $options['tid'] = $transactionId; + $options['updateId'] = $transactionId; + } + $this->saveResult = Syntrans::addWithNotes( $spelling, $languageId, $definedMeaningId, $identicalMeaning, $options ); + + } + + private function process() { + global $myWordnikAPIKey, $wgWldProcessExternalAPIClasses, $wgOut; + + // limit access to wikidata editors + if ( !$this->getUser()->isAllowed( 'editwikidata-uw' ) ) { + $this->dieUsage( 'you must have a WikiLexicalData edit flag to use this page', 'wld_edit_only' ); + } + + // keep blocked users out + if ( $this->getUser()->isBlocked() ) { + $this->dieUsage( 'your account is blocked.', 'blocked' ); + } + + $sourceLanguageId = array_key_exists( 'from-lang', $_GET ) ? $_GET['from-lang'] : ''; + $source = array_key_exists( 'api', $_GET ) ? $_GET['api'] : ''; + $search = array_key_exists( 'search-ext', $_GET ) ? $_GET['search-ext'] : ''; + $collectionId = array_key_exists( 'collection', $_GET ) ? $_GET['collection'] : ''; + + switch ( $source ) { + case 'Wordnik' : $this->requireWordnik(); break; + case 'Wordnik-Wiktionary' : $this->requireWordnik(); break; + case 'Wordnik-Wordnet' : $this->requireWordnik(); break; + } + + $externalResourceClass = 'ExternalResources'; + if ( $source ) { + foreach( $wgWldProcessExternalAPIClasses as $sourceClass => $sourceValue ) { + if ( $source === $sourceClass ) { + $externalResourceClass = $sourceClass; + } + } + } + + $handlerInstance = new $externalResourceClass( + wfMessage( 'ow_addFromExtAPI_title' )->text(), + $source, + $sourceLanguageId, + $search, + $collectionId + ); + $handlerInstance->execute(); + } + + /** execute the special page. + * + * separates the save from the process functions + */ + function execute( $par ) { + $this->saveType = array_key_exists( 'save-data', $_POST ) ? $_POST['save-data'] : ''; + if ( $this->saveType ) { $this->save();} + else { $this->process();} + } + + protected function requireWordik() { + require_once( 'ExternalWordnik.php' ); + } + +} + +/** @brief This class handles External Resources. + * + * This class is the base of individual external resources + * + * @note: To extend this class, the extended class needs its own __construct, execute, + * checkExternalDefinition, setExternalDefinition functions. + * + */ +class ExternalResources { + + protected $wgOut; + protected $externalLexicalData = array(); + protected $owlLexicalData = array(); + protected $spTitle; + protected $source; + protected $sourceLanguageId; + protected $collectionId; + protected $externalDefinition; + protected $externalExists = false; // bool + protected $owlDefinition; + protected $owlExists = false; // bool + + + /** + * @param spTitle str Special Page Title + * @param source str the source dictionary + * @param sourceLabel str the source dictionary name that will appear. + * @param sourceLanguageId int The languageId of the source dictionary + * @param search str The expression/spelling( word ) to be searched + * @param collectionId int The Collection Id + */ + function __construct( $spTitle, $source, $sourceLanguageId, $search, $collectionId ) { + global $wgOut; + $this->wgOut = $wgOut; + $this->spTitle = $spTitle; + $this->source = $source; + $this->sourceLabel = $source; + $this->sourceLanguageId = $sourceLanguageId; + $this->search = $search; + $this->collectionId = $collectionId; + } + + public function execute() { + $this->outputTitle(); + $this->getOptionPanel(); + $this->checkConnectionStatus(); + + // inline css ( for future refactoring ) + // removes from data when finished testing + $this->wgOut->addHTML( $this->temporaryCodeSpace() ); + + if ( $this->source ) { + switch ( $this->connection ) { + case true: + $this->checkExternalDefinition(); + $this->checkOmegaWikiDefinition(); + if ( $this->externalExists and $this->owlExists ) { + $this->setExternalDefinition(); + $this->setOmegaWikiDefinition(); + $this->createChoice(); + } + break; + case false: + $this->wgOut->addHtml( 'Sorry, there is a problem with the connection. Can not find ' . $this->search ); + break; + } + } + } + + private function temporaryCodeSpace() { + return '<style>' . + '#ext-data {visibility: hidden; display: none }' . + '#owl-data {visibility: hidden; display: none }' . + '</style>'; + } + + private function createChoice() { + $owlLineProcessed = false; + $ctr = 0; + $this->wgOut->addHTML( + '<form id="flexible_form">'. + '<input type="hidden" name="title" value="Special:Ow addFromExtAPI"/>' + ); + $this->wgOut->addHTML( + '<div><div id="owl_def"></div><div id="ext_def"></div><span id="selectChecks"><input type="button" id="inputSelectButton" value="process"/></span><span id="skipChecks"><input type="button" id="inputSkipSelectButton" value="next"/></span></div>' + ); + $this->wgOut->addHTML( + '</form>' + ); + } + + private function outputTitle() { + $this->wgOut->setPageTitle( $this->spTitle ); + } + + private function getOptionPanel() { + global $wgWldProcessExternalAPIClasses, $wgWldExtenalResourceLanguages; + $forms = new OmegaWikiForms; + $this->wgOut->addHTML( getOptionPanel( + array( + wfMessage( 'ow_api_source' )->text() => $forms->getSelect( 'api', $wgWldProcessExternalAPIClasses, $this->source ), + wfMessage( 'ow_needs_xlation_source_lang' )->text() => $forms->getSelect( 'from-lang', $wgWldExtenalResourceLanguages, $this->sourceLanguageId ), + wfMessage( 'datasearch_search_text' )->text() => getTextBox( 'search-ext', $this->search ), + ) + ) ); + } + + /** + */ + function checkConnectionStatus() { + $this->connection = false; + if ( connection_status() === CONNECTION_NORMAL ) { + $this->connection = true; + } + } + + protected function outputResult() { + if ( $this->externalLexicalData ) { + $this->wgOut->addHTML( json_encode( $this->externalLexicalData ) . '<br/><br/>.' ); + } else { + } + if ( $this->owlLexicalData ) { + $this->wgOut->addHTML( json_encode( $this->owlLexicalData ) . '<br/><br/>' ); + } else { + } + } + + protected function checkOmegaWikiDefinition() { + if ( existSpelling( $this->search, $this->sourceLanguageId ) ) { + $this->owlExists = true; + } + } + + protected function setOmegaWikiDefinition() { + // If expression exist in the source language, then proceed. + if ( existSpelling( $this->search, $this->sourceLanguageId ) ) { + $this->expressionId = OwDatabaseAPI::getTheExpressionId( $this->search, $this->sourceLanguageId ); + $dmList = OwDatabaseAPI::getExpressionMeaningIdsForLanguages( $this->search, $this->sourceLanguageId ); + foreach( $dmList as $dmLine ) { + $text = getDefinedMeaningDefinitionForLanguage( $dmLine, $this->sourceLanguageId ); + if ( !$text ) { + $text = getDefinedMeaningDefinitionForLanguage( $dmLine, WLD_ENGLISH_LANG_ID ); + } + + $synonyms = OwDatabaseAPI::getSynonyms( $dmLine, $this->sourceLanguageId, $this->search ); + + $this->owlLexicalData[] = array( + 'processed' => null, + 'e' => $this->search, + 'dm_id' => $dmLine, + 'lang_id' => $this->sourceLanguageId, + 'text' => $text, + 'syn' => $synonyms + ); + } + } + + $this->owlLexicalDataJSON = json_encode( $this->owlLexicalData ); + // Line below for testing. When there's no internet connection + // $this->owlLexicalDataJSON = '[{"processed":null,"dm_id":"5836","lang_id":"85","text":"A common, four-legged animal (Sus scrofa) that has cloven hooves, bristles and a nose adapted for digging and is farmed by humans for its meat.","syn":null},{"processed":null,"dm_id":"1499810","lang_id":"85","text":"(Pejorative) A fat or overweight person.","syn":[["butterball","85","1","1499814"],["chubster","85","1","1499816"],["chunker","85","1","1499818"],["fat-ass","85","1","1499825"],["fatass","85","1","1499827"],["fatfuck","85","1","1499820"],["fatshit","85","1","1499829"],["fatso","85","1","1499811"],["fattie","85","1","1499822"],["fatty","85","1","1499823"],["lardass","85","1","1499831"],["lardo","85","1","1499833"],["obeast","85","1","1499837"],["oinker","85","1","1499835"],["podge","85","1","1499840"],["porker","85","1","1499842"],["pudge","85","1","1499844"],["salad dodger","85","1","1499846"],["tub of lard","85","1","1499848"]]},{"processed":null,"dm_id":"583600","lang_id":"85","text":"A common, four-legged animal (Sus scrofa) that has cloven hooves, bristles and a nose adapted for digging and is farmed by humans for its meat.","syn":null}]'; + + $this->wgOut->addHTML( + '<div id="owl-data">' . $this->owlLexicalDataJSON . '</div>' + ); + } + +} diff --git a/resources/omegawiki-addExtAPI.js b/resources/omegawiki-addExtAPI.js new file mode 100644 index 0000000..fdeedbe --- /dev/null +++ b/resources/omegawiki-addExtAPI.js @@ -0,0 +1,348 @@ +// hide these buttons even before the document is ready. +$('#ext-data').hide(); +$('#owl-data').hide(); +$('#owl_def').hide(''); +$('#ext_def').hide(''); +$('#flexible_form').hide(); +$('#inputSelectButton').hide(); +$('#inputSkipSelectButton').hide(); + +jQuery(document).ready( function( $ ) { + + $('#flexible_form').slideDown( 'slow' ); + createExternalAPIDataChoice(); + + // process the selected items at flexible forms + $('#selectChecks').on('click', function(event) { + var selectValue = $('#inputSelectButton').val(); + if ( selectValue === 'process' ) { + processSelectChecksPhaseOne(); + } + + if ( selectValue === 'submit' ) { + processSelectChecksPhaseTwo(); + } + }); + + // skip the selected items at flexible forms + $('#skipChecks').on('click', function(event) { + createExternalAPIDataChoice(); + + $('input.choices').on('click', function(event) { + checkInputChoices( this ); + }); + + $('input.choosing').on('click', function(event) { + checkInputChoices( this ); + }); + + }); + + // toggle input.choices' value ( null or the value of $(this).attr('name') ) + $('input.choices').on('click', function(event) { + checkInputChoices( this ); + }); + + // toggle input.choosing' value ( null or the value of $(this).attr('name') ) + $('input.choosing').on('click', function(event) { + checkInputChoices( this ); + }); + + function checkInputChoices( selectorName ) { + if ( $(selectorName).val() === '' ) { + if( !$(selectorName).attr('name') ) { + $(selectorName).val( 'selected' ); + } else { + $(selectorName).val( $(selectorName).attr('name') ); + } + } else { + $(selectorName).val( '' ); + } + console.log( 'value changed to ' + $(selectorName).val() ); + } + + // adds the necessary output to the screen + function createExternalAPIDataChoice() { + $('#owl_def').slideUp(''); + $('#ext_def').slideUp(''); + var owlExists = nextOwlExists(); // check if there are still DM to process + + if( owlExists === true ) { + var owlLineProcessed = false; + var addOwlHtml = ''; + var addExtHtml = '<table><tr>'; + + $('#inputSelectButton').attr( 'value', 'process' ).show(); + $('#inputSkipSelectButton').attr( 'value', 'next' ).show(); + + // get owlLexicalData + var owlLexicalData = getOwlData(); + + var ctr = 0; + owlLexicalData.forEach( function( oLine ) { + // if( owlLineProcessed === false && owlLexicalData[ctr]['processed'] === null ) { + if( owlLineProcessed === false && owlLexicalData[ctr].processed === null ) { + owlLineProcessed = true; + // owlLexicalData[ctr]['processed'] = true; + owlLexicalData[ctr].processed = true; + if ( oLine.syn === null ) { + oLineSyn = ''; + } else { + oLineSyn = JSON.stringify( oLine.syn ); + } + addOwlHtml = + '<h2>DefinedMeaning:' + oLine.e + ' (' + oLine.dm_id + ')</h2>' + oLine.text + + '<span id="owl_def_syn" style="visibility:hidden;display:none;">' + + oLineSyn + '</span><hr/>\n' + ; + $('#owl_def').attr( 'dm_id', oLine.dm_id ); + $('#owl_def').attr( 'lang_id', oLine.lang_id ); + $('#owl_def').html( addOwlHtml ); + $('#owl_def').slideDown('slow'); + + } + ctr++; + }); + + // get extLexicalData + var extLexicalData = getExtData(); + + ctr = 0; + extLexicalData.forEach( function( eLine ) { + addExtHtml = addExtHtml + '<td><input class="choices" name="' + ctr + '" value="" type="checkbox"/>' + + eLine.src + '</td><td>' + eLine.partOfSpeech + '</td><td>' + eLine.text + '</td></tr><tr>\n'; + ctr++; + }); + addExtHtml = addExtHtml + '</tr></table>'; + + // refresh flexible_form id + $('#ext_def').html( addExtHtml ); + $('#ext_def').slideDown('slow'); + + // refresh owl-data id + owlData = JSON.stringify( owlLexicalData ); + $('#owl-data').text( owlData ); + } else { + resetFlexibleForm(); + $('#owl_def').text( 'Finished. No more DefinedMeaning to process.' ).slideDown('slow'); + } + return true; + } + + // @return array either the external data or an empty array + function getExtData() { + var thisData = []; + var extData = $('#ext-data').text(); + if ( extData ) { + thisData = JSON.parse( extData ); + } + return thisData; + } + + // @return HTML string of synonyms from external source to choose from. + function getExtSynonym( rwWords, dmId, langId, src ) { + var includedWord = ''; + rwWords.forEach(function( theWord ){ + var owlDefSyn = $('#owl_def_syn').text(); + var includeTheWord = true; + if ( owlDefSyn !== '' ) { + owlDefSyn = JSON.parse( owlDefSyn ); + owlDefSyn.forEach( function( owlSynonym ) { + if ( theWord === owlSynonym[0] ) { + includeTheWord = false; + } + }); + } + if ( includeTheWord === true ) { + includedWord += + '<td><input class="choosing" value="" type="checkbox" ' + + 'action="owAddSyntrans" ' + + 'e="' + theWord + '" ' + + 'dm="' + dmId + '" ' + + 'lang="' + langId + '" ' + + 'src="' + src + '" ' + + 'im="' + '' + '" ' + // he: future implementation? + '/>' + + 'add synonym' + '</td><td>' + theWord + '</td><td>~ ' + src + '</td></tr>\n<tr>'; + } + }); + return includedWord; + } + + // @return array either the OmegaWikiLexical data or an empty array + function getOwlData() { + var thisData = []; + var owlData = $('#owl-data').text(); + if ( owlData ) { + thisData = JSON.parse( owlData ); + } + return thisData; + } + + // checks if there are still DMs to process + function nextOwlExists() { + owlData = getOwlData(); + owlExists = false; + owlData.forEach( function( data ) { if ( data.processed === null) { + owlExists = true; + }}); + return owlExists; + } + + function processSelectChecksPhaseOne() { + var extDef = $('#ext_def').html(); + var owlDef = $('#owl_def').html(); + var dmId = $('#owl_def').attr('dm_id'); + var langId = $('#owl_def').attr('lang_id'); + var extData = getExtData(); + var myChoices = extDef.match( /value="\d+"/gm ); + + if ( !myChoices ) { + alert( 'No definition selected.' ); + } else { + var addExtHtml = ''; + + var ctr = 0; + extData.forEach(function( definition ) { + if( definition.relatedWords ) { + definition.relatedWords.forEach( function( rw ) { + myChoices.forEach( function( myChoiceLine ) { + ctrChoice = myChoiceLine.match( /\d+/ ) + '.'; + if ( ctr + '.' === ctrChoice ) { + if( rw.relationshipType === 'synonym' ) { + // console.log( rw['words'] ); + addExtHtml += getExtSynonym( rw['words'], dmId, langId, definition.src ); + } + } + }); + }); + } + ctr++; + }); + + if( addExtHtml !== '' ) { + $('#ext_def').slideUp(); + $('#inputSelectButton').attr( 'value', 'submit' ); + $('#inputSkipSelectButton').attr( 'value', 'skip' ); + var addExtHtml = '<table><tr>' + addExtHtml + '</tr></table>'; + $('#ext_def').html( addExtHtml ); + $('#ext_def').slideDown(); + } else { + if ( nextOwlExists() === true ) { + alert( 'Nothing to add.\nSkipping to next definition.'); + } else { + alert( 'Nothing to add.\nNo more DefinedMeaning left.'); + } + createExternalAPIDataChoice(); + } + + } + + $('input.choices').on('click', function(event) { + checkInputChoices( this ); + }); + + $('input.choosing').on('click', function(event) { + checkInputChoices( this ); + }); + + } + + function processSelectChecksPhaseTwo() { + var URL = mw.config.get( 'wgServer' ) + mw.config.get( 'wgScript' ); + URL = URL + '/Special:Ow_addFromExtAPI'; + console.log( 'Website:' + URL ); + var myChoices = []; + console.log( 'choosing search result: ' + $('#ext_def').html().search( /<input class="choosing".+value="selected".+type="checkbox">/gm ) ); + if ( $('#ext_def').html().search( /<input class="choosing".+value="selected".+type="checkbox">/gm ) !== -1 ) { + console.log( 'found choosing' ); + myChoices = $('#ext_def').html().match( /<input class="choosing".+value="selected".+type="checkbox">/gm ); + } else { + alert( 'nothing selected' ); + } + + var tid = null; + var processHowMany = myChoices.length; + var processedAll = 0; + var processStatement = ''; + + myChoices.forEach( function( line ){ + console.log( line + ' :' + typeof line ); + var exp = line.match( / e=".+" dm/ ).shift().match( /".+"/ ).shift().slice( 1, -1 ); + var dmId = line.match( / dm="\d+"/ ).shift().match( /\d+/ ).shift(); + var langId = line.match( / lang="\d+"/ ).shift().match( /\d+/ ).shift(); + var src = line.match( / src=".+" im/ ).shift().match( /".+"/ ).shift().slice( 1, -1 ); + + saveData = { + 'e': exp, + 'dm-id': dmId, + 'lang-id': langId, + 'src': src, + 'save-data':'synonym', + 'printable':'yes' + }; + + if ( tid !== null ) { + saveData.tid = '' + tid; + saveData.transacted = true; + } + + $.post( URL, saveData, function( data, status ) { + console.log( 'Data: ' + data + '\nStatus: ' + status ); + // data = JSON.parse( '{' + data + '}' ); + data = JSON.parse( data ); + if ( data.note !== 'test run only' ) { + tid = data.tid; + } + if ( !data.note ) { + data.note = ''; + } else { + data.note += '.'; + } + + processStatement += data.status + ' '; + if ( data.status === 'exists' ) { + processStatement = '<br>\n' + data.e + ' ' + processStatement + 'in ' + data.in; + // processStatement += ' in ' + data.in; + } else { + processStatement = '<br>\n' + processStatement + data.e +' to ' + data.to; + } + processStatement += '. ' + data.note + '<br/>\n' + ; + processedAll++; + + if ( processedAll === processHowMany ) { + processStatement += '<br\n>'; + console.log( processStatement ); + // remove ext_def and replace with statement + $('#ext_def').html( processStatement ); + $('#inputSelectButton').hide(); + $('#inputSkipSelectButton').attr( 'value', 'next' ); + } + + }); + + }); + + + $('input.choices').on('click', function(event) { + checkInputChoices( this ); + }); + + $('input.choosing').on('click', function(event) { + checkInputChoices( this ); + }); + + } + + // basically, blanks the output divs + function resetFlexibleForm() { + $('#owl_def').text(''); + $('#ext_def').text(''); + $('#owl-data').text(''); + $('#ext-data').text(''); + $('#inputSelectButton').hide(); + $('#inputSkipSelectButton').hide(); + } + +}); -- To view, visit https://gerrit.wikimedia.org/r/158842 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I36b6e537d8ee518a7bb2146bf09327bc2161ccf0 Gerrit-PatchSet: 3 Gerrit-Project: mediawiki/extensions/WikiLexicalData Gerrit-Branch: master Gerrit-Owner: Hiong3-eng5 <hiong3.e...@gmail.com> Gerrit-Reviewer: Kipcool <kipmas...@gmail.com> Gerrit-Reviewer: Siebrand <siebr...@kitano.nl> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits