Merge pull request #2756 from OpenRefine/wikidata-extension-oauth
Wikidata extension two-legged OAuth support
This commit is contained in:
commit
b59228185e
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 24 KiB |
@ -43,9 +43,7 @@
|
||||
"wikidata-account/dialog-header": "উইকিউপাত্ত অ্যাকাউন্ট",
|
||||
"wikidata-account/explain-log-in": "<a href=\"https://www.wikidata.org/\" target=\"_blank\">উইকিউপাত্তে</a> প্রবেশ করলে সরাসরি ওপেনরিফাইন থেকে আপনাকে সম্পাদনা আপলোড করতে দেওয়া হবে।",
|
||||
"wikidata-account/username-label": "ব্যবহারকারী নাম:",
|
||||
"wikidata-account/username-placeholder": "আপনার ব্যবহারকারী নাম অন্তর্ভুক্ত করুন",
|
||||
"wikidata-account/password-label": "পাসওয়ার্ড:",
|
||||
"wikidata-account/password-placeholder": "আপনার পাসওয়ার্ড অন্তর্ভুক্ত করুন",
|
||||
"wikidata-account/close": "বন্ধ করুন",
|
||||
"wikidata-account/log-in": "প্রবেশ করুন",
|
||||
"wikidata-account/log-out": "প্রস্থান করুন"
|
||||
|
@ -65,11 +65,25 @@
|
||||
"wikidata-preview/new-id": "new item",
|
||||
"wikidata-account/dialog-header": "Wikidata account",
|
||||
"wikidata-account/explain-log-in": "Logging in to <a href=\"https://www.wikidata.org/\" target=\"_blank\">Wikidata</a> lets you to upload edits directly from OpenRefine.",
|
||||
"wikidata-account/explain-owner-only-consumer-wiki": "See this <a href=\"https://github.com/OpenRefine/OpenRefine/wiki/Wikidata-owner-only-consumer\" target=\"_blank\">wiki</a> to get your owner-only consumer if you don't have one.",
|
||||
"wikidata-account/explain-password-login": "You can also <a>login with your username/password.</a>",
|
||||
"wikidata-account/explain-owner-only-consumer-login": "You can also <a>login with your owner-only consumer.</a>",
|
||||
"wikidata-account/invalid-credentials": "Invalid credentials",
|
||||
"wikidata-account/username-label": "Username:",
|
||||
"wikidata-account/username-placeholder": "Enter your username",
|
||||
"wikidata-account/username-placeholder": "username",
|
||||
"wikidata-account/password-label": "Password:",
|
||||
"wikidata-account/password-placeholder": "Enter your password",
|
||||
"wikidata-account/remember-credentials-label": "Remember credentials (stored unencrypted in OpenRefine's preferences)",
|
||||
"wikidata-account/password-placeholder": "password",
|
||||
"wikidata-account/consumer-token-label": "Consumer token:",
|
||||
"wikidata-account/consumer-token-placeholder": "consumer token",
|
||||
"wikidata-account/consumer-secret-label": "Consumer secret:",
|
||||
"wikidata-account/consumer-secret-placeholder": "consumer secret",
|
||||
"wikidata-account/access-token-label": "Access token:",
|
||||
"wikidata-account/access-token-placeholder": "access token",
|
||||
"wikidata-account/access-secret-label": "Access secret:",
|
||||
"wikidata-account/access-secret-placeholder": "access secret",
|
||||
"wikidata-account/remember-me": "Remember me",
|
||||
"wikidata-account/password-remember-me-title": "Your password won't be stored. Don't check this if your computer is public.",
|
||||
"wikidata-account/owner-only-consumer-remember-me-title": "Consumer credentials are stored unencrypted in cookies. Don't check this if your computer is public.",
|
||||
"wikidata-account/close": "Close",
|
||||
"wikidata-account/log-in": "Log in",
|
||||
"wikidata-account/logged-in-as": "You are logged in as:",
|
||||
|
@ -95,17 +95,31 @@
|
||||
"perform-wikidata-edits/review-your-edits": "You are about to upload {nb_edits} edits to Wikidata. Please check them carefully. Large edit batches should be submitted for <a href=\"https://www.wikidata.org/wiki/Wikidata:Requests_for_permissions/Bot\" target=\"_blank\">bot review</a> first.",
|
||||
"perform-wikidata-edits/dialog-header": "Upload edits to Wikidata",
|
||||
"wikidata-account/connecting-to-wikidata": "Connecting to Wikidata…",
|
||||
"wikidata-account/log-out": "Log out",
|
||||
"wikidata-account/logged-in-as": "You are logged in as:",
|
||||
"wikidata-account/log-in": "Log in",
|
||||
"wikidata-account/close": "Close",
|
||||
"wikidata-account/remember-credentials-label": "Remember credentials (stored unencrypted in OpenRefine's preferences)",
|
||||
"wikidata-account/password-placeholder": "Enter your password",
|
||||
"wikidata-account/password-label": "Password:",
|
||||
"wikidata-account/username-placeholder": "Enter your username",
|
||||
"wikidata-account/username-label": "Username:",
|
||||
"wikidata-account/explain-log-in": "Logging in to <a href=\"https://www.wikidata.org/\" target=\"_blank\">Wikidata</a> lets you to upload edits directly from OpenRefine.",
|
||||
"wikidata-account/dialog-header": "Wikidata account",
|
||||
"wikidata-account/explain-log-in": "Logging in to <a href=\"https://www.wikidata.org/\" target=\"_blank\">Wikidata</a> lets you to upload edits directly from OpenRefine.",
|
||||
"wikidata-account/explain-owner-only-consumer-wiki": "See this <a href=\"https://github.com/OpenRefine/OpenRefine/wiki/Wikidata-owner-only-consumer\" target=\"_blank\">wiki</a> to get your owner-only consumer if you don't have one.",
|
||||
"wikidata-account/explain-password-login": "You can also <a>login with your username/password.</a>",
|
||||
"wikidata-account/explain-owner-only-consumer-login": "You can also <a>login with your owner-only consumer.</a>",
|
||||
"wikidata-account/invalid-credentials": "Invalid credentials",
|
||||
"wikidata-account/username-label": "Username:",
|
||||
"wikidata-account/username-placeholder": "username",
|
||||
"wikidata-account/password-label": "Password:",
|
||||
"wikidata-account/password-placeholder": "password",
|
||||
"wikidata-account/consumer-token-label": "Consumer token:",
|
||||
"wikidata-account/consumer-token-placeholder": "consumer token",
|
||||
"wikidata-account/consumer-secret-label": "Consumer secret:",
|
||||
"wikidata-account/consumer-secret-placeholder": "consumer secret",
|
||||
"wikidata-account/access-token-label": "Access token:",
|
||||
"wikidata-account/access-token-placeholder": "access token",
|
||||
"wikidata-account/access-secret-label": "Access secret:",
|
||||
"wikidata-account/access-secret-placeholder": "access secret",
|
||||
"wikidata-account/remember-me": "Remember me",
|
||||
"wikidata-account/password-remember-me-title": "Your password won't be stored. Don't check this if your computer is public.",
|
||||
"wikidata-account/owner-only-consumer-remember-me-title": "Consumer credentials are stored unencrypted in cookies. Don't check this if your computer is public.",
|
||||
"wikidata-account/close": "Close",
|
||||
"wikidata-account/log-in": "Log in",
|
||||
"wikidata-account/logged-in-as": "You are logged in as:",
|
||||
"wikidata-account/log-out": "Log out",
|
||||
"wikidata-preview/new-id": "new item",
|
||||
"wikidata-schema/unsaved-warning": "You have made unsaved changes to your Wikidata schema. Close anyway?",
|
||||
"wikidata-schema/incomplete-schema-could-not-be-saved": "Your schema is incomplete so it cannot be saved yet.",
|
||||
|
@ -59,10 +59,7 @@
|
||||
"wikidata-account/dialog-header": "compte Wikidata",
|
||||
"wikidata-account/explain-log-in": "Se connecter à <a href=\"https://www.wikidata.org/\" target=\"_blank\">Wikidata</a> vous permet de publier vos données sur Wikidata depuis OpenRefine.",
|
||||
"wikidata-account/username-label": "Nom d'utilisateur :",
|
||||
"wikidata-account/username-placeholder": "Entrez votre nom d'utilisateur",
|
||||
"wikidata-account/password-label": "Mot de passe :",
|
||||
"wikidata-account/password-placeholder": "Entrez votre mot de passe",
|
||||
"wikidata-account/remember-credentials-label": "Se souvenir des identifiants (enregistrés sans chiffrement dans les préférences)",
|
||||
"wikidata-account/close": "Fermer",
|
||||
"wikidata-account/log-in": "Se connecter",
|
||||
"wikidata-account/logged-in-as": "Vous êtes connecté·e en tant que :",
|
||||
|
@ -52,10 +52,7 @@
|
||||
"wikidata-account/dialog-header": "account su Wikidata",
|
||||
"wikidata-account/explain-log-in": "Accedere a <a href=\"https://www.wikidata.org/\" target=\"_blank\">Wikidata</a> ti permette di caricare i tuoi edit direttamente tramite OpenRefine.",
|
||||
"wikidata-account/username-label": "Nome utente:",
|
||||
"wikidata-account/username-placeholder": "Inserisci il tuo nome utente",
|
||||
"wikidata-account/password-label": "Password:",
|
||||
"wikidata-account/password-placeholder": "Inserisci la tua password",
|
||||
"wikidata-account/remember-credentials-label": "Ricorda questi dati (verranno mantenuti in forma criptata nelle preferenze di OpenRefine",
|
||||
"wikidata-account/close": "Chiudi",
|
||||
"wikidata-account/log-in": "Entra",
|
||||
"wikidata-account/logged-in-as": "Sei registrato come:",
|
||||
|
@ -56,10 +56,7 @@
|
||||
"wikidata-account/dialog-header": "Wikidataアカウント",
|
||||
"wikidata-account/explain-log-in": "OpenRefineから直接データをアップロードするため、<a href=\"https://www.wikidata.org/\" target=\"_blank\">Wikidata</a>にログインする.",
|
||||
"wikidata-account/username-label": "ユーザー名:",
|
||||
"wikidata-account/username-placeholder": "ユーザー名を入力",
|
||||
"wikidata-account/password-label": "パスワード:",
|
||||
"wikidata-account/password-placeholder": "パスワードを入力",
|
||||
"wikidata-account/remember-credentials-label": "credentialsをOpenRefineの設定に保存する",
|
||||
"wikidata-account/close": "閉じる",
|
||||
"wikidata-account/log-in": "ログイン",
|
||||
"wikidata-account/logged-in-as": "ログイン名:",
|
||||
|
@ -54,10 +54,7 @@
|
||||
"wikidata-account/dialog-header": "Wikidata 계정",
|
||||
"wikidata-account/explain-log-in": "<a href=\"https://www.wikidata.org/\" target=\"_blank\">Wikidata</a> 로그인하세요. OpenRefine 에서 직접 편집을 업로드할 수 있습니다.",
|
||||
"wikidata-account/username-label": "사용자이름:",
|
||||
"wikidata-account/username-placeholder": "사용자이름을 입력하세요",
|
||||
"wikidata-account/password-label": "비밀번호:",
|
||||
"wikidata-account/password-placeholder": "비밀번호를 입력하세요",
|
||||
"wikidata-account/remember-credentials-label": "credentials을 기억하세요 (OpenRefine의 Preferences에 암호화되지 않고 저장됩니다)",
|
||||
"wikidata-account/close": "닫기",
|
||||
"wikidata-account/log-in": "로그인",
|
||||
"wikidata-account/logged-in-as": "다음으로 로그인 됨:",
|
||||
|
@ -54,10 +54,7 @@
|
||||
"wikidata-account/dialog-header": "Wikidata-konto",
|
||||
"wikidata-account/explain-log-in": "Hvis du logger inn på <a href=\"https://www.wikidata.org/\" target=\"_blank\">Wikidata</a> kan du laste opp redigeringer direkte fra OpenRefine.",
|
||||
"wikidata-account/username-label": "Brukernavn:",
|
||||
"wikidata-account/username-placeholder": "Skriv inn brukernavnet ditt",
|
||||
"wikidata-account/password-label": "Passord:",
|
||||
"wikidata-account/password-placeholder": "Skriv inn passordet ditt",
|
||||
"wikidata-account/remember-credentials-label": "Husk meg (lagres ukryptert i OpenRefines innstillinger)",
|
||||
"wikidata-account/close": "Lukk",
|
||||
"wikidata-account/log-in": "Logg inn",
|
||||
"wikidata-account/logged-in-as": "Du er innlogget som:",
|
||||
|
@ -53,10 +53,7 @@
|
||||
"wikidata-account/dialog-header": "Wikidata-account",
|
||||
"wikidata-account/explain-log-in": "Aanmelden bij <a href=\"https://www.wikidata.org/\" target=\"_blank\">Wikidata</a> laat u direct bewerkingen vanuit OpenRefine uploaden.",
|
||||
"wikidata-account/username-label": "Gebruikersnaam:",
|
||||
"wikidata-account/username-placeholder": "Vul uw gebruikersnaam in",
|
||||
"wikidata-account/password-label": "Wachtwoord:",
|
||||
"wikidata-account/password-placeholder": "Voer uw wachtwoord in",
|
||||
"wikidata-account/remember-credentials-label": "Gegevens onthouden (ongecodeerd opgeslagen in de voorkeuren van OpenRefine)",
|
||||
"wikidata-account/close": "Sluiten",
|
||||
"wikidata-account/log-in": "Aanmelden",
|
||||
"wikidata-account/logged-in-as": "U bent aangemeld als:",
|
||||
|
@ -59,10 +59,7 @@
|
||||
"wikidata-preview/new-id": "nytt objekt",
|
||||
"wikidata-account/explain-log-in": "Logga in på <a href=\"https://www.wikidata.org/\" target=\"_blank\">Wikidata</a> så att du kan ladda upp redigeringar direkt från OpenRefine.",
|
||||
"wikidata-account/username-label": "Användarnamn:",
|
||||
"wikidata-account/username-placeholder": "Skriv in ditt användarnamn",
|
||||
"wikidata-account/password-label": "Lösenord:",
|
||||
"wikidata-account/password-placeholder": "Skriv in ditt lösenord",
|
||||
"wikidata-account/remember-credentials-label": "Kom ihåg inloggningsuppgifter (lagras okrypterade i OpenRefines inställningar)",
|
||||
"wikidata-account/connecting-to-wikidata": "Anslut till Wikidata…",
|
||||
"perform-wikidata-edits/dialog-header": "Överför redigeringar till Wikidata",
|
||||
"perform-wikidata-edits/review-your-edits": "Du håller på att ladda upp {nb_edits} redigeringar till Wikidata. Kontrollera dem noggrant. Stora antal av ändringar bör skickas till <a href=\"https://www.wikidata.org/wiki/Wikidata:Requests_for_permissions/Bot\" target=\"_blank\">botgranskning</a> först.",
|
||||
|
@ -5,7 +5,7 @@
|
||||
<label for="schema" bind="schemaLabel"></label><br />
|
||||
<textarea name="schema" class="wikibase-schema-textarea" bind="schemaTextarea"></textarea><br />
|
||||
<div class="wikibase-invalid-schema" bind="invalidSchema"></div>
|
||||
<div class="wikibase-login-buttons">
|
||||
<div class="wikibase-import-schema-buttons">
|
||||
<button class="button cancel-button" bind="cancelButton"></button>
|
||||
<button class="button button-primary" bind="importButton"></button>
|
||||
</div>
|
||||
|
@ -0,0 +1,23 @@
|
||||
<div class="dialog-frame" style="width: 800px;">
|
||||
<div class="dialog-header" bind="dialogHeader"></div>
|
||||
<div class="dialog-body" bind="dialogBody" style="position: relative; height: 100px">
|
||||
<div class="wikidata-logo">
|
||||
<a href="https://www.wikidata.org/" target="_blank">
|
||||
<img src="extension/wikidata/images/wikidata.png" style="height: 100px" alt="Wikidata logo"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="right-of-logo">
|
||||
<p class="body-text" bind="explainLogIn"></p>
|
||||
<div class="wikibase-user-management-area">
|
||||
<div class="wikibase-user-logout" bind="logoutArea">
|
||||
<p><span bind="loggedInAs"></span>
|
||||
<a bind="loggedInUsername" target="_blank"></a></p>
|
||||
<div class="wikibase-login-buttons">
|
||||
<button class="button cancel-button" bind="cancelButton"></button>
|
||||
<button class="button button-primary" bind="logoutButton"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,45 +0,0 @@
|
||||
<div class="dialog-frame" style="width: 800px;">
|
||||
<div class="dialog-header" bind="dialogHeader"></div>
|
||||
<div class="dialog-body" bind="dialogBody">
|
||||
<a href="https://www.wikidata.org/" target="_blank">
|
||||
<img src="extension/wikidata/images/wikidata.png" class="wikidata-logo" alt="Wikidata logo" />
|
||||
</a>
|
||||
<div class="right-of-logo">
|
||||
<p class="body-text" bind="explainLogIn">
|
||||
</p>
|
||||
<div class="wikibase-user-management-area">
|
||||
<div class="wikibase-user-login" bind="loginArea">
|
||||
<div bind="invalidCredentials" class="wikibase-invalid-credentials"></div>
|
||||
<form bind="loginForm" class="wikibase-login-form" method="post">
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="wb-username" bind="usernameLabel"></label></td>
|
||||
<td><input name="wb-username" type="text" bind="usernameInput" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="wb-password" bind="passwordLabel"></label></td>
|
||||
<td><input name="wb-password" type="password" bind="passwordInput" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="remember-credentials" /></td>
|
||||
<td><label for="remember-credentials" bind="rememberCredentialsLabel"></label></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="wikibase-login-buttons">
|
||||
<button class="button cancel-button" type="button" bind="cancelButton1"></button>
|
||||
<input class="button button-primary" type="submit" bind="loginButton"></input>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="wikibase-user-logout" bind="logoutArea">
|
||||
<p><span bind="loggedInAs"></span>
|
||||
<a bind="loggedInUsername" target="_blank"></a></p>
|
||||
<div class="wikibase-login-buttons">
|
||||
<button class="button cancel-button" bind="cancelButton2"></button>
|
||||
<button class="button button-primary" bind="logoutButton"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -2,60 +2,112 @@ var ManageAccountDialog = {};
|
||||
|
||||
ManageAccountDialog.firstLogin = true;
|
||||
|
||||
ManageAccountDialog.launch = function(logged_in_username, callback) {
|
||||
$.post(
|
||||
"command/core/get-all-preferences",
|
||||
null,
|
||||
function (preferences) {
|
||||
ManageAccountDialog.display(logged_in_username, preferences.wikidata_credentials, callback);
|
||||
},
|
||||
"json"
|
||||
);
|
||||
/**
|
||||
* Displays the logged in page if the user is logged in,
|
||||
* displays the login page otherwise.
|
||||
*/
|
||||
ManageAccountDialog.display = function (logged_in_username, onSuccess) {
|
||||
if (logged_in_username == null) {
|
||||
if (ManageAccountDialog.firstLogin) {
|
||||
ManageAccountDialog.firstLogin = false;
|
||||
ManageAccountDialog.tryLoginWithCookies(onSuccess);
|
||||
} else {
|
||||
ManageAccountDialog.displayPasswordLogin(onSuccess);
|
||||
}
|
||||
} else {
|
||||
ManageAccountDialog.displayLoggedIn(logged_in_username);
|
||||
}
|
||||
};
|
||||
|
||||
ManageAccountDialog.display = function(logged_in_username, saved_credentials, callback) {
|
||||
var self = this;
|
||||
var frame = $(DOM.loadHTML("wikidata", "scripts/dialogs/manage-account-dialog.html"));
|
||||
var elmts = this._elmts = DOM.bind(frame);
|
||||
|
||||
this._elmts.dialogHeader.text($.i18n('wikidata-account/dialog-header'));
|
||||
this._elmts.explainLogIn.html($.i18n('wikidata-account/explain-log-in'));
|
||||
this._elmts.usernameLabel.text($.i18n('wikidata-account/username-label'));
|
||||
this._elmts.usernameInput.attr("placeholder", $.i18n('wikidata-account/username-placeholder'));
|
||||
this._elmts.passwordLabel.text($.i18n('wikidata-account/password-label'));
|
||||
this._elmts.passwordInput.attr("placeholder", $.i18n('wikidata-account/password-placeholder'));
|
||||
this._elmts.rememberCredentialsLabel.text($.i18n('wikidata-account/remember-credentials-label'));
|
||||
this._elmts.dialogHeader.text($.i18n('wikidata-account/dialog-header'));
|
||||
this._elmts.cancelButton1.text($.i18n('wikidata-account/close'));
|
||||
this._elmts.cancelButton2.text($.i18n('wikidata-account/close'));
|
||||
this._elmts.loggedInAs.text($.i18n('wikidata-account/logged-in-as'));
|
||||
this._elmts.logoutButton.text($.i18n('wikidata-account/log-out'));
|
||||
this._elmts.loginButton.val($.i18n('wikidata-account/log-in'));
|
||||
|
||||
if (logged_in_username != null) {
|
||||
elmts.loginArea.remove();
|
||||
ManageAccountDialog.tryLoginWithCookies = function (onSuccess) {
|
||||
// In the first login, we try logging in with cookies,
|
||||
// the backend may take a while to tell if the cookies are valid or not.
|
||||
// So we need to call DialogSystem.showBusy to inform the user that
|
||||
// OpenRefine is trying connecting to Wikidata.
|
||||
const discardWaiter = DialogSystem.showBusy($.i18n('wikidata-account/connecting-to-wikidata'));
|
||||
Refine.postCSRF(
|
||||
"command/wikidata/login",
|
||||
{},
|
||||
function (data) {
|
||||
discardWaiter();
|
||||
if (data.logged_in) {
|
||||
onSuccess(data.username);
|
||||
ManageAccountDialog.displayLoggedIn(data.username);
|
||||
} else {
|
||||
elmts.logoutArea.remove();
|
||||
ManageAccountDialog.displayPasswordLogin(onSuccess);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this._level = DialogSystem.showDialog(frame);
|
||||
this._elmts.usernameInput.focus();
|
||||
ManageAccountDialog.initCommon = function (elmts) {
|
||||
elmts.dialogHeader.text($.i18n('wikidata-account/dialog-header'));
|
||||
elmts.explainLogIn.html($.i18n('wikidata-account/explain-log-in'));
|
||||
elmts.cancelButton.text($.i18n('wikidata-account/close'));
|
||||
};
|
||||
|
||||
ManageAccountDialog.displayLoggedIn = function (logged_in_username) {
|
||||
var frame = $(DOM.loadHTML("wikidata", "scripts/dialogs/logged-in-dialog.html"));
|
||||
var elmts = DOM.bind(frame);
|
||||
ManageAccountDialog.initCommon(elmts);
|
||||
elmts.loggedInAs.text($.i18n('wikidata-account/logged-in-as'));
|
||||
elmts.logoutButton.text($.i18n('wikidata-account/log-out'));
|
||||
|
||||
var level = DialogSystem.showDialog(frame);
|
||||
var dismiss = function () {
|
||||
DialogSystem.dismissUntil(self._level - 1);
|
||||
DialogSystem.dismissUntil(level - 1);
|
||||
};
|
||||
|
||||
elmts.loggedInUsername
|
||||
.text(logged_in_username)
|
||||
.attr('href', 'https://www.wikidata.org/wiki/User:' + logged_in_username);
|
||||
|
||||
elmts.cancelButton1.click(function(e) {
|
||||
elmts.cancelButton.click(function (e) {
|
||||
dismiss();
|
||||
callback(null);
|
||||
});
|
||||
elmts.cancelButton2.click(function(e) {
|
||||
|
||||
elmts.logoutButton.click(function () {
|
||||
frame.hide();
|
||||
Refine.postCSRF(
|
||||
"command/wikidata/login",
|
||||
"logout=true",
|
||||
function (data) {
|
||||
frame.show();
|
||||
if (!data.logged_in) {
|
||||
dismiss();
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ManageAccountDialog.displayPasswordLogin = function (onSuccess) {
|
||||
const frame = $(DOM.loadHTML("wikidata", "scripts/dialogs/password-login-dialog.html"));
|
||||
const elmts = DOM.bind(frame);
|
||||
ManageAccountDialog.initCommon(elmts);
|
||||
elmts.explainOwnerOnlyConsumerLogin.html($.i18n('wikidata-account/explain-owner-only-consumer-login'));
|
||||
elmts.invalidCredentials.text($.i18n('wikidata-account/invalid-credentials'));
|
||||
elmts.invalidCredentials.hide();
|
||||
elmts.usernameLabel.text($.i18n('wikidata-account/username-label'));
|
||||
elmts.usernameInput.attr("placeholder", $.i18n('wikidata-account/username-placeholder'));
|
||||
elmts.passwordLabel.text($.i18n('wikidata-account/password-label'));
|
||||
elmts.passwordInput.attr("placeholder", $.i18n('wikidata-account/password-placeholder'));
|
||||
elmts.rememberMe.text($.i18n('wikidata-account/remember-me'));
|
||||
elmts.passwordRememberMeTitle.attr("title", $.i18n('wikidata-account/password-remember-me-title'));
|
||||
elmts.loginButton.text($.i18n('wikidata-account/log-in'));
|
||||
elmts.usernameInput.focus();
|
||||
|
||||
var level = DialogSystem.showDialog(frame);
|
||||
var dismiss = function () {
|
||||
DialogSystem.dismissUntil(level - 1);
|
||||
};
|
||||
|
||||
elmts.cancelButton.click(function (e) {
|
||||
dismiss();
|
||||
});
|
||||
|
||||
elmts.explainOwnerOnlyConsumerLogin.click(function (e) {
|
||||
dismiss();
|
||||
ManageAccountDialog.displayOwnerOnlyConsumerLogin(onSuccess);
|
||||
});
|
||||
|
||||
elmts.loginForm.submit(function (e) {
|
||||
@ -66,56 +118,98 @@ ManageAccountDialog.display = function(logged_in_username, saved_credentials, ca
|
||||
function (data) {
|
||||
if (data.logged_in) {
|
||||
dismiss();
|
||||
callback(data.username);
|
||||
}
|
||||
else {
|
||||
onSuccess(data.username);
|
||||
} else {
|
||||
frame.show();
|
||||
elmts.invalidCredentials.text("Invalid credentials.");
|
||||
elmts.invalidCredentials.show();
|
||||
}
|
||||
});
|
||||
e.preventDefault();
|
||||
}
|
||||
);
|
||||
|
||||
elmts.logoutButton.click(function() {
|
||||
Refine.postCSRF(
|
||||
"command/wikidata/login",
|
||||
"logout=true",
|
||||
function(data) {
|
||||
if (!data.logged_in) {
|
||||
dismiss();
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ManageAccountDialog.isLoggedIn = function(callback) {
|
||||
var discardWaiter = function() { };
|
||||
if(ManageAccountDialog.firstLogin) {
|
||||
discardWaiter = DialogSystem.showBusy($.i18n('wikidata-account/connecting-to-wikidata'));
|
||||
ManageAccountDialog.displayOwnerOnlyConsumerLogin = function (onSuccess) {
|
||||
var frame = $(DOM.loadHTML("wikidata", "scripts/dialogs/owner-only-consumer-login-dialog.html"));
|
||||
var elmts = DOM.bind(frame);
|
||||
ManageAccountDialog.initCommon(elmts);
|
||||
elmts.explainOwnerOnlyConsumerWiki.html($.i18n('wikidata-account/explain-owner-only-consumer-wiki'));
|
||||
elmts.explainPasswordLogin.html($.i18n('wikidata-account/explain-password-login'));
|
||||
elmts.invalidCredentials.text($.i18n('wikidata-account/invalid-credentials'));
|
||||
elmts.invalidCredentials.hide();
|
||||
elmts.consumerTokenLabel.text($.i18n('wikidata-account/consumer-token-label'));
|
||||
elmts.consumerTokenInput.attr("placeholder", $.i18n('wikidata-account/consumer-token-placeholder'));
|
||||
elmts.consumerSecretLabel.text($.i18n('wikidata-account/consumer-secret-label'));
|
||||
elmts.consumerSecretInput.attr("placeholder", $.i18n('wikidata-account/consumer-secret-placeholder'));
|
||||
elmts.accessTokenLabel.text($.i18n('wikidata-account/access-token-label'));
|
||||
elmts.accessTokenInput.attr("placeholder", $.i18n('wikidata-account/access-token-placeholder'));
|
||||
elmts.accessSecretLabel.text($.i18n('wikidata-account/access-secret-label'));
|
||||
elmts.accessSecretInput.attr("placeholder", $.i18n('wikidata-account/access-secret-placeholder'));
|
||||
elmts.rememberMe.text($.i18n('wikidata-account/remember-me'));
|
||||
elmts.ownerOnlyConsumerRememberMeTitle.attr("title", $.i18n('wikidata-account/owner-only-consumer-remember-me-title'));
|
||||
elmts.loginButton.text($.i18n('wikidata-account/log-in'));
|
||||
elmts.consumerTokenInput.focus();
|
||||
|
||||
var level = DialogSystem.showDialog(frame);
|
||||
var dismiss = function () {
|
||||
DialogSystem.dismissUntil(level - 1);
|
||||
};
|
||||
|
||||
elmts.cancelButton.click(function (e) {
|
||||
dismiss();
|
||||
});
|
||||
|
||||
elmts.explainPasswordLogin.click(function (e) {
|
||||
dismiss();
|
||||
ManageAccountDialog.displayPasswordLogin(onSuccess);
|
||||
});
|
||||
|
||||
elmts.loginForm.submit(function (e) {
|
||||
frame.hide();
|
||||
Refine.postCSRF(
|
||||
"command/wikidata/login",
|
||||
elmts.loginForm.serialize(),
|
||||
function (data) {
|
||||
if (data.logged_in) {
|
||||
dismiss();
|
||||
onSuccess(data.username);
|
||||
} else {
|
||||
frame.show();
|
||||
elmts.invalidCredentials.show();
|
||||
}
|
||||
});
|
||||
e.preventDefault();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the user is logged in or not.
|
||||
*
|
||||
* The callback needs to react to both cases.
|
||||
*/
|
||||
ManageAccountDialog.isLoggedIn = function (callback) {
|
||||
$.get(
|
||||
"command/wikidata/login",
|
||||
function (data) {
|
||||
discardWaiter();
|
||||
ManageAccountDialog.firstLogin = false;
|
||||
callback(data.username);
|
||||
});
|
||||
};
|
||||
|
||||
ManageAccountDialog.ensureLoggedIn = function(callback) {
|
||||
/**
|
||||
* The onSuccess callback is called if and only if the user is logged in.
|
||||
*/
|
||||
ManageAccountDialog.ensureLoggedIn = function (onSuccess) {
|
||||
ManageAccountDialog.isLoggedIn(function (logged_in_username) {
|
||||
if (logged_in_username == null) {
|
||||
ManageAccountDialog.launch(null, callback);
|
||||
ManageAccountDialog.display(null, onSuccess);
|
||||
} else {
|
||||
callback(logged_in_username);
|
||||
onSuccess(logged_in_username);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ManageAccountDialog.checkAndLaunch = function () {
|
||||
ManageAccountDialog.isLoggedIn(function (logged_in_username) {
|
||||
ManageAccountDialog.launch(logged_in_username, function(success) { });
|
||||
ManageAccountDialog.display(logged_in_username, function (success) {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -0,0 +1,53 @@
|
||||
<div class="dialog-frame" style="width: 800px;">
|
||||
<div class="dialog-header" bind="dialogHeader"></div>
|
||||
<div class="dialog-body" bind="dialogBody" style="position: relative; height: 240px">
|
||||
<div class="wikidata-logo">
|
||||
<a href="https://www.wikidata.org/" target="_blank">
|
||||
<img src="extension/wikidata/images/wikidata.png" alt="Wikidata logo"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="right-of-logo">
|
||||
<p class="body-text" bind="explainLogIn"></p>
|
||||
<p class="body-text" bind="explainOwnerOnlyConsumerWiki"></p>
|
||||
<div class="wikibase-user-management-area">
|
||||
<div class="wikibase-user-login" bind="loginArea">
|
||||
<p bind="invalidCredentials" class="wikibase-invalid-credentials"></p>
|
||||
<form bind="loginForm" class="wikibase-login-form" method="post">
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="wb-consumer-token" bind="consumerTokenLabel"></label></td>
|
||||
<td><input name="wb-consumer-token" id="wb-consumer-token" type="text" bind="consumerTokenInput"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="wb-consumer-secret" bind="consumerSecretLabel"></label></td>
|
||||
<td><input name="wb-consumer-secret" id="wb-consumer-secret" type="password" bind="consumerSecretInput"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="wb-access-token" bind="accessTokenLabel"></label></td>
|
||||
<td><input name="wb-access-token" id="wb-access-token" type="text" bind="accessTokenInput"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="wb-access-secret" bind="accessSecretLabel"></label></td>
|
||||
<td><input name="wb-access-secret" id="wb-access-secret" type="password" bind="accessSecretInput"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="remember-credentials" id="remember-credentials" bind="rememberCredentials"/></td>
|
||||
<td>
|
||||
<span><label for="remember-credentials"bind="rememberMe"></label></span>
|
||||
<span><img src="extension/wikidata/images/Information.png" style="height: 0.8rem;" alt="information" bind="ownerOnlyConsumerRememberMeTitle"/></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="wikibase-login-buttons">
|
||||
<button class="button cancel-button" type="button" bind="cancelButton"></button>
|
||||
<button class="button button-primary" type="submit" bind="loginButton"></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-footer wikibase-login-dialog-footer">
|
||||
<span bind="explainPasswordLogin"></span>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,46 @@
|
||||
<div class="dialog-frame" style="width: 800px;">
|
||||
<div class="dialog-header" bind="dialogHeader"></div>
|
||||
<div class="dialog-body" bind="dialogBody" style="position: relative; height: 140px">
|
||||
<div class="wikidata-logo">
|
||||
<a href="https://www.wikidata.org/" target="_blank">
|
||||
<img src="extension/wikidata/images/wikidata.png" alt="Wikidata logo"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="right-of-logo">
|
||||
<p class="body-text" bind="explainLogIn"></p>
|
||||
<div class="wikibase-user-management-area">
|
||||
<div class="wikibase-user-login" bind="loginArea">
|
||||
<p bind="invalidCredentials" class="wikibase-invalid-credentials"></p>
|
||||
<form bind="loginForm" class="wikibase-login-form" method="post">
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="wb-username" bind="usernameLabel"></label></td>
|
||||
<td><input name="wb-username" id="wb-username" type="text" bind="usernameInput"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="wb-password" bind="passwordLabel"></label></td>
|
||||
<td><input name="wb-password" id="wb-password" type="password" bind="passwordInput"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="remember-credentials" id="remember-credentials" bind="rememberCredentials"/></td>
|
||||
<td>
|
||||
<span><label for="remember-credentials"bind="rememberMe"></label></span>
|
||||
<span><img src="extension/wikidata/images/Information.png" style="height: 0.8rem;" alt="information" bind="passwordRememberMeTitle"/></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="wikibase-login-buttons">
|
||||
<button class="button cancel-button" type="button" bind="cancelButton"></button>
|
||||
<button class="button button-primary" type="submit" bind="loginButton"></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-footer wikibase-login-dialog-footer">
|
||||
<span bind="explainOwnerOnlyConsumerLogin"></span>
|
||||
</div>
|
||||
</div>
|
@ -7,9 +7,9 @@
|
||||
</div>
|
||||
<div class="wikibase-perform-edits-area">
|
||||
<form id="wikibase-perform-edits-form" onsubmit="return false;" bind="performEditsForm" autocomplete="on">
|
||||
<p><span bind="loggedInAs"></span> <a bind="loggedInUsername" target="_blank"></a>.</p>
|
||||
<p style="margin-top: 0.5rem; margin-bottom: 0.5rem"><span bind="loggedInAs"></span> <a bind="loggedInUsername" target="_blank"></a>.</p>
|
||||
<p><span bind="editSummaryLabel"></span> <input type="text" name="editSummary" bind="editSummary" class="edit-summary" value="" /></p>
|
||||
<div class="wikibase-login-buttons">
|
||||
<div class="wikibase-perform-edits-buttons">
|
||||
<button class="button cancel-button" bind="cancelButton"></button>
|
||||
<button class="button button-primary" bind="performEditsButton"></button>
|
||||
</div>
|
||||
|
@ -42,7 +42,7 @@ PerformEditsDialog.launch = function(logged_in_username, max_severity) {
|
||||
{ onDone: function() { dismiss(); } }
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
elmts.loggedInUsername
|
||||
.text(logged_in_username)
|
||||
@ -72,7 +72,7 @@ PerformEditsDialog.updateEditCount = function(edit_count) {
|
||||
this._elmts.reviewYourEdits.html(
|
||||
$.i18n('perform-wikidata-edits/review-your-edits')
|
||||
.replace('{nb_edits}', edit_count));
|
||||
}
|
||||
};
|
||||
|
||||
PerformEditsDialog._updateWarnings = function(data) {
|
||||
var warnings = data.warnings;
|
||||
@ -87,7 +87,7 @@ PerformEditsDialog._updateWarnings = function(data) {
|
||||
var rendered = WarningsRenderer._renderWarning(warnings[i]);
|
||||
rendered.appendTo(table);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PerformEditsDialog.checkAndLaunch = function () {
|
||||
var self = this;
|
||||
@ -97,7 +97,6 @@ PerformEditsDialog.checkAndLaunch = function () {
|
||||
|
||||
var onSaved = function () {
|
||||
ManageAccountDialog.ensureLoggedIn(function (logged_in_username) {
|
||||
if (logged_in_username) {
|
||||
var discardWaiter = DialogSystem.showBusy($.i18n('perform-wikidata-edits/analyzing-edits'));
|
||||
Refine.postCSRF(
|
||||
"command/wikidata/preview-wikibase-schema?" + $.param({project: theProject.id}),
|
||||
@ -114,7 +113,6 @@ PerformEditsDialog.checkAndLaunch = function () {
|
||||
},
|
||||
"json"
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -8,3 +8,4 @@
|
||||
.wikibase-schema-textarea {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
}
|
||||
|
@ -37,12 +37,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wikibase-login-buttons {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.wikibase-invalid-credentials {
|
||||
color: red;
|
||||
padding-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.wikibase-user-login tr td {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.wikibase-user-login tr td:first-child {
|
||||
@ -55,10 +56,39 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
|
||||
.wikidata-logo {
|
||||
height: 100%;
|
||||
float: left;
|
||||
margin: -10px;
|
||||
margin-right: 50px;
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.right-of-logo {
|
||||
margin-left: 110px;
|
||||
.wikidata-logo img {
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.wikibase-login-buttons {
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
bottom: 12px;
|
||||
}
|
||||
|
||||
|
||||
.wikibase-perform-edits-buttons {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.wikibase-import-schema-buttons {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
.wikibase-login-dialog-footer {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wikibase-login-dialog-footer span {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
34
extensions/wikidata/module/styles/theme.less
Normal file
34
extensions/wikidata/module/styles/theme.less
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
|
||||
Copyright 2011, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
@import-less url("../../../../main/webapp/modules/core/styles/theme.less");
|
@ -16,7 +16,7 @@
|
||||
|
||||
<properties>
|
||||
<powermock.version>2.0.7</powermock.version>
|
||||
<wdtk.version>0.11.1</wdtk.version>
|
||||
<wdtk.version>0.12.0-SNAPSHOT</wdtk.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@ -127,17 +127,17 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wikidata.wdtk</groupId>
|
||||
<groupId>org.openrefine.dependencies.wdtk</groupId>
|
||||
<artifactId>wdtk-wikibaseapi</artifactId>
|
||||
<version>${wdtk.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wikidata.wdtk</groupId>
|
||||
<groupId>org.openrefine.dependencies.wdtk</groupId>
|
||||
<artifactId>wdtk-datamodel</artifactId>
|
||||
<version>${wdtk.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wikidata.wdtk</groupId>
|
||||
<groupId>org.openrefine.dependencies.wdtk</groupId>
|
||||
<artifactId>wdtk-util</artifactId>
|
||||
<version>${wdtk.version}</version>
|
||||
</dependency>
|
||||
|
@ -6,6 +6,7 @@ import java.io.Writer;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.google.refine.commands.Command;
|
||||
import com.google.refine.util.ParsingUtilities;
|
||||
|
||||
public class CommandUtilities {
|
||||
|
@ -0,0 +1,219 @@
|
||||
/*******************************************************************************
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2018 Antonin Delpeuch
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.openrefine.wikidata.commands;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.refine.ProjectManager;
|
||||
import com.google.refine.preference.PreferenceStore;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.wikidata.wdtk.wikibaseapi.ApiConnection;
|
||||
import org.wikidata.wdtk.wikibaseapi.BasicApiConnection;
|
||||
import org.wikidata.wdtk.wikibaseapi.LoginFailedException;
|
||||
import org.wikidata.wdtk.wikibaseapi.OAuthApiConnection;
|
||||
import org.wikidata.wdtk.wikibaseapi.apierrors.MediaWikiApiErrorException;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Manages a connection to Wikidata.
|
||||
* <p>
|
||||
* The connection can be either {@link BasicApiConnection} or {@link OAuthApiConnection}.
|
||||
* <p>
|
||||
* This class is also hard-coded for Wikidata,
|
||||
* it will be generalized to other Wikibase instances soon.
|
||||
*
|
||||
* @author Antonin Delpeuch
|
||||
* @author Lu Liu
|
||||
*/
|
||||
|
||||
public class ConnectionManager {
|
||||
|
||||
final static Logger logger = LoggerFactory.getLogger("connection_manager");
|
||||
|
||||
/**
|
||||
* We used this key to read/write credentials from/to preferences in the past, which is insecure.
|
||||
* Now this key is kept only to delete those credentials in the preferences.
|
||||
*/
|
||||
public static final String PREFERENCE_STORE_KEY = "wikidata_credentials";
|
||||
|
||||
public static final int CONNECT_TIMEOUT = 5000;
|
||||
public static final int READ_TIMEOUT = 10000;
|
||||
|
||||
/**
|
||||
* For now, this class is hard-coded for Wikidata.
|
||||
* <p>
|
||||
* It will be generalized to work against other Wikibase instances in the future.
|
||||
*/
|
||||
private static final String WIKIBASE_API_ENDPOINT = ApiConnection.URL_WIKIDATA_API;
|
||||
|
||||
/**
|
||||
* The single {@link ApiConnection} instance managed by {@link ConnectionManager}.
|
||||
* <p>
|
||||
* Currently, only one connection is supported at the same time.
|
||||
*/
|
||||
private ApiConnection connection;
|
||||
|
||||
private static final ConnectionManager instance = new ConnectionManager();
|
||||
|
||||
public static ConnectionManager getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ConnectionManager() {
|
||||
PreferenceStore prefStore = ProjectManager.singleton.getPreferenceStore();
|
||||
// remove credentials stored in the preferences
|
||||
prefStore.put(PREFERENCE_STORE_KEY, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs in to the Wikibase instance, using username/password.
|
||||
* <p>
|
||||
* If failed to login, the connection will be set to null.
|
||||
*
|
||||
* @param username the username to log in with
|
||||
* @param password the password to log in with
|
||||
* @return true if logged in successfully, false otherwise
|
||||
*/
|
||||
public boolean login(String username, String password) {
|
||||
connection = new BasicApiConnection(WIKIBASE_API_ENDPOINT);
|
||||
setupConnection(connection);
|
||||
try {
|
||||
((BasicApiConnection) connection).login(username, password);
|
||||
return true;
|
||||
} catch (LoginFailedException e) {
|
||||
logger.error(e.getMessage());
|
||||
connection = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs in to the Wikibase instance, using owner-only consumer.
|
||||
* <p>
|
||||
* If failed to login, the connection will be set to null.
|
||||
*
|
||||
* @param consumerToken consumer token of an owner-only consumer
|
||||
* @param consumerSecret consumer secret of an owner-only consumer
|
||||
* @param accessToken access token of an owner-only consumer
|
||||
* @param accessSecret access secret of an owner-only consumer
|
||||
* @return true if logged in successfully, false otherwise
|
||||
*/
|
||||
public boolean login(String consumerToken, String consumerSecret,
|
||||
String accessToken, String accessSecret) {
|
||||
connection = new OAuthApiConnection(WIKIBASE_API_ENDPOINT,
|
||||
consumerToken, consumerSecret,
|
||||
accessToken, accessSecret);
|
||||
setupConnection(connection);
|
||||
try {
|
||||
// check if the credentials are valid
|
||||
connection.checkCredentials();
|
||||
return true;
|
||||
} catch (IOException | MediaWikiApiErrorException e) {
|
||||
logger.error(e.getMessage());
|
||||
connection = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Logs in to the Wikibase instance, using cookies.
|
||||
* <p>
|
||||
* If failed to login, the connection will be set to null.
|
||||
*
|
||||
* @param username the username
|
||||
* @param cookies the cookies used to login
|
||||
* @return true if logged in successfully, false otherwise
|
||||
*/
|
||||
public boolean login(String username, List<Cookie> cookies) {
|
||||
cookies.forEach(cookie -> cookie.setPath("/"));
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("baseUrl", WIKIBASE_API_ENDPOINT);
|
||||
map.put("cookies", cookies);
|
||||
map.put("username", username);
|
||||
map.put("loggedIn", true);
|
||||
map.put("tokens", Collections.emptyMap());
|
||||
map.put("connectTimeout", CONNECT_TIMEOUT);
|
||||
map.put("readTimeout", READ_TIMEOUT);
|
||||
try {
|
||||
BasicApiConnection newConnection = convertToBasicApiConnection(map);
|
||||
newConnection.checkCredentials();
|
||||
connection = newConnection;
|
||||
return true;
|
||||
} catch (IOException | MediaWikiApiErrorException e) {
|
||||
logger.error(e.getMessage());
|
||||
connection = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For testability.
|
||||
*/
|
||||
static BasicApiConnection convertToBasicApiConnection(Map<String, Object> map) throws JsonProcessingException {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String json = mapper.writeValueAsString(map);
|
||||
return mapper.readValue(json, BasicApiConnection.class);
|
||||
}
|
||||
|
||||
|
||||
public void logout() {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.logout();
|
||||
connection = null;
|
||||
} catch (IOException | MediaWikiApiErrorException e) {
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ApiConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
public boolean isLoggedIn() {
|
||||
return connection != null;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
if (connection != null) {
|
||||
return connection.getCurrentUser();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupConnection(ApiConnection connection) {
|
||||
connection.setConnectTimeout(CONNECT_TIMEOUT);
|
||||
connection.setReadTimeout(READ_TIMEOUT);
|
||||
}
|
||||
}
|
@ -23,21 +23,48 @@
|
||||
******************************************************************************/
|
||||
package org.openrefine.wikidata.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import com.google.refine.commands.Command;
|
||||
import org.wikidata.wdtk.wikibaseapi.ApiConnection;
|
||||
import org.wikidata.wdtk.wikibaseapi.BasicApiConnection;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.openrefine.wikidata.editing.ConnectionManager;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.google.refine.commands.Command;
|
||||
import com.google.refine.util.ParsingUtilities;
|
||||
import static org.apache.commons.lang.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang.StringUtils.isNotBlank;
|
||||
|
||||
/**
|
||||
* Handles login.
|
||||
* <p>
|
||||
* Both logging in with username/password or owner-only consumer are supported.
|
||||
* <p>
|
||||
* This command also manages cookies of login credentials.
|
||||
*/
|
||||
public class LoginCommand extends Command {
|
||||
|
||||
static final String WIKIDATA_COOKIE_PREFIX = "openrefine-wikidata-";
|
||||
|
||||
static final String WIKIBASE_USERNAME_COOKIE_KEY = "wikibase-username";
|
||||
|
||||
static final String USERNAME = "wb-username";
|
||||
static final String PASSWORD = "wb-password";
|
||||
|
||||
static final String CONSUMER_TOKEN = "wb-consumer-token";
|
||||
static final String CONSUMER_SECRET = "wb-consumer-secret";
|
||||
static final String ACCESS_TOKEN = "wb-access-token";
|
||||
static final String ACCESS_SECRET = "wb-access-secret";
|
||||
|
||||
@Override
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
@ -45,34 +72,110 @@ public class LoginCommand extends Command {
|
||||
respondCSRFError(response);
|
||||
return;
|
||||
}
|
||||
respond(request, response);
|
||||
}
|
||||
|
||||
protected void respond(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
String username = request.getParameter("wb-username");
|
||||
String password = request.getParameter("wb-password");
|
||||
String remember = request.getParameter("remember-credentials");
|
||||
ConnectionManager manager = ConnectionManager.getInstance();
|
||||
if (username != null && password != null) {
|
||||
manager.login(username, password, "on".equals(remember));
|
||||
} else if ("true".equals(request.getParameter("logout"))) {
|
||||
|
||||
if ("true".equals(request.getParameter("logout"))) {
|
||||
manager.logout();
|
||||
removeUsernamePasswordCookies(request, response);
|
||||
removeOwnerOnlyConsumerCookies(request, response);
|
||||
respond(request, response);
|
||||
return; // return directly
|
||||
}
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setHeader("Content-Type", "application/json");
|
||||
|
||||
Writer w = response.getWriter();
|
||||
JsonGenerator writer = ParsingUtilities.mapper.getFactory().createGenerator(w);
|
||||
boolean remember = "on".equals(request.getParameter("remember-credentials"));
|
||||
|
||||
writer.writeStartObject();
|
||||
writer.writeBooleanField("logged_in", manager.isLoggedIn());
|
||||
writer.writeStringField("username", manager.getUsername());
|
||||
writer.writeEndObject();
|
||||
writer.flush();
|
||||
writer.close();
|
||||
w.flush();
|
||||
w.close();
|
||||
// Credentials from parameters have higher priority than those from cookies.
|
||||
String username = request.getParameter(USERNAME);
|
||||
String password = request.getParameter(PASSWORD);
|
||||
String consumerToken = request.getParameter(CONSUMER_TOKEN);
|
||||
String consumerSecret = request.getParameter(CONSUMER_SECRET);
|
||||
String accessToken = request.getParameter(ACCESS_TOKEN);
|
||||
String accessSecret = request.getParameter(ACCESS_SECRET);
|
||||
|
||||
if (isBlank(username) && isBlank(password) && isBlank(consumerToken) &&
|
||||
isBlank(consumerSecret) && isBlank(accessToken) && isBlank(accessSecret)) {
|
||||
// In this case, we use cookie to login, and we will always remember the credentials in cookies.
|
||||
remember = true;
|
||||
Cookie[] cookies = request.getCookies();
|
||||
|
||||
for (Cookie cookie : cookies) {
|
||||
String value = getCookieValue(cookie);
|
||||
switch (cookie.getName()) {
|
||||
case CONSUMER_TOKEN:
|
||||
consumerToken = value;
|
||||
break;
|
||||
case CONSUMER_SECRET:
|
||||
consumerSecret = value;
|
||||
break;
|
||||
case ACCESS_TOKEN:
|
||||
accessToken = value;
|
||||
break;
|
||||
case ACCESS_SECRET:
|
||||
accessSecret = value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isBlank(consumerToken) && isBlank(consumerSecret) && isBlank(accessToken) && isBlank(accessSecret)) {
|
||||
// Try logging in with the cookies of a password-based connection.
|
||||
String username1 = null;
|
||||
List<Cookie> cookieList = new ArrayList<>();
|
||||
for (Cookie cookie : cookies) {
|
||||
if (cookie.getName().startsWith(WIKIDATA_COOKIE_PREFIX)) {
|
||||
String cookieName = cookie.getName().substring(WIKIDATA_COOKIE_PREFIX.length());
|
||||
Cookie newCookie = new Cookie(cookieName, getCookieValue(cookie));
|
||||
cookieList.add(newCookie);
|
||||
} else if (cookie.getName().equals(WIKIBASE_USERNAME_COOKIE_KEY)) {
|
||||
username1 = getCookieValue(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
if (cookieList.size() > 0 && username1 != null) {
|
||||
removeOwnerOnlyConsumerCookies(request, response);
|
||||
if (manager.login(username1, cookieList)) {
|
||||
respond(request, response);
|
||||
return;
|
||||
} else {
|
||||
removeUsernamePasswordCookies(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNotBlank(username) && isNotBlank(password)) {
|
||||
// Once logged in with new credentials,
|
||||
// the old credentials in cookies should be cleared.
|
||||
if (manager.login(username, password) && remember) {
|
||||
ApiConnection connection = manager.getConnection();
|
||||
List<HttpCookie> cookies = ((BasicApiConnection) connection).getCookies();
|
||||
for (HttpCookie cookie : cookies) {
|
||||
setCookie(response, WIKIDATA_COOKIE_PREFIX + cookie.getName(), cookie.getValue());
|
||||
}
|
||||
|
||||
// Though the cookies from the connection contain some cookies of username,
|
||||
// we cannot make sure that all Wikibase instances use the same cookie key
|
||||
// to retrieve the username. So we choose to set the username cookie with our own cookie key.
|
||||
setCookie(response, WIKIBASE_USERNAME_COOKIE_KEY, connection.getCurrentUser());
|
||||
} else {
|
||||
removeUsernamePasswordCookies(request, response);
|
||||
}
|
||||
removeOwnerOnlyConsumerCookies(request, response);
|
||||
} else if (isNotBlank(consumerToken) && isNotBlank(consumerSecret) && isNotBlank(accessToken) && isNotBlank(accessSecret)) {
|
||||
if (manager.login(consumerToken, consumerSecret, accessToken, accessSecret) && remember) {
|
||||
setCookie(response, CONSUMER_TOKEN, consumerToken);
|
||||
setCookie(response, CONSUMER_SECRET, consumerSecret);
|
||||
setCookie(response, ACCESS_TOKEN, accessToken);
|
||||
setCookie(response, ACCESS_SECRET, accessSecret);
|
||||
} else {
|
||||
removeOwnerOnlyConsumerCookies(request, response);
|
||||
}
|
||||
removeUsernamePasswordCookies(request, response);
|
||||
}
|
||||
|
||||
respond(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -80,4 +183,51 @@ public class LoginCommand extends Command {
|
||||
throws ServletException, IOException {
|
||||
respond(request, response);
|
||||
}
|
||||
|
||||
protected void respond(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
ConnectionManager manager = ConnectionManager.getInstance();
|
||||
Map<String, Object> jsonResponse = new HashMap<>();
|
||||
jsonResponse.put("logged_in", manager.isLoggedIn());
|
||||
jsonResponse.put("username", manager.getUsername());
|
||||
respondJSON(response, jsonResponse);
|
||||
}
|
||||
|
||||
private static void removeUsernamePasswordCookies(HttpServletRequest request, HttpServletResponse response) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
for (Cookie cookie : cookies) {
|
||||
if (cookie.getName().startsWith(WIKIDATA_COOKIE_PREFIX)) {
|
||||
removeCookie(response, cookie.getName());
|
||||
}
|
||||
}
|
||||
removeCookie(response, WIKIBASE_USERNAME_COOKIE_KEY);
|
||||
}
|
||||
|
||||
private static void removeOwnerOnlyConsumerCookies(HttpServletRequest request, HttpServletResponse response) {
|
||||
removeCookie(response, CONSUMER_TOKEN);
|
||||
removeCookie(response, CONSUMER_SECRET);
|
||||
removeCookie(response, ACCESS_TOKEN);
|
||||
removeCookie(response, ACCESS_SECRET);
|
||||
}
|
||||
|
||||
static String getCookieValue(Cookie cookie) throws UnsupportedEncodingException {
|
||||
return URLDecoder.decode(cookie.getValue(), "utf-8");
|
||||
}
|
||||
|
||||
private static void setCookie(HttpServletResponse response, String key, String value) throws UnsupportedEncodingException {
|
||||
String encodedValue = URLEncoder.encode(value, "utf-8");
|
||||
Cookie cookie = new Cookie(key, encodedValue);
|
||||
cookie.setMaxAge(60 * 60 * 24 * 365); // a year
|
||||
cookie.setPath("/");
|
||||
// set to false because OpenRefine doesn't require HTTPS
|
||||
cookie.setSecure(false);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
private static void removeCookie(HttpServletResponse response, String key) {
|
||||
Cookie cookie = new Cookie(key, "");
|
||||
cookie.setMaxAge(0); // 0 causes the cookie to be deleted
|
||||
cookie.setPath("/");
|
||||
cookie.setSecure(false);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
}
|
||||
|
@ -1,171 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2018 Antonin Delpeuch
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.openrefine.wikidata.editing;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.wikidata.wdtk.wikibaseapi.ApiConnection;
|
||||
import org.wikidata.wdtk.wikibaseapi.BasicApiConnection;
|
||||
import org.wikidata.wdtk.wikibaseapi.LoginFailedException;
|
||||
import org.wikidata.wdtk.wikibaseapi.apierrors.MediaWikiApiErrorException;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.google.refine.ProjectManager;
|
||||
import com.google.refine.preference.PreferenceStore;
|
||||
import com.google.refine.util.ParsingUtilities;
|
||||
|
||||
/**
|
||||
* Manages a connection to Wikidata, with login credentials stored in the
|
||||
* preferences.
|
||||
*
|
||||
* Ideally, we should store only the cookies and not the password. But
|
||||
* Wikidata-Toolkit does not allow for that as cookies are kept private.
|
||||
*
|
||||
* This class is also hard-coded for Wikidata: generalization to other Wikibase
|
||||
* instances should be feasible though.
|
||||
*
|
||||
* @author Antonin Delpeuch
|
||||
*/
|
||||
|
||||
public class ConnectionManager {
|
||||
|
||||
final static Logger logger = LoggerFactory.getLogger("connection_mananger");
|
||||
|
||||
public static final String PREFERENCE_STORE_KEY = "wikidata_credentials";
|
||||
public static final int CONNECT_TIMEOUT = 5000;
|
||||
public static final int READ_TIMEOUT = 10000;
|
||||
|
||||
private PreferenceStore prefStore;
|
||||
private BasicApiConnection connection;
|
||||
|
||||
private static final ConnectionManager instance = new ConnectionManager();
|
||||
|
||||
public static ConnectionManager getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a connection manager, which attempts to restore any
|
||||
* previous connection (from the preferences).
|
||||
*/
|
||||
private ConnectionManager() {
|
||||
prefStore = ProjectManager.singleton.getPreferenceStore();
|
||||
connection = null;
|
||||
restoreSavedConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs in to the Wikibase instance, using login/password
|
||||
*
|
||||
* @param username
|
||||
* the username to log in with
|
||||
* @param password
|
||||
* the password to log in with
|
||||
* @param rememberCredentials
|
||||
* whether to store these credentials in the preferences (unencrypted!)
|
||||
*/
|
||||
public void login(String username, String password, boolean rememberCredentials) {
|
||||
if (rememberCredentials) {
|
||||
ArrayNode array = ParsingUtilities.mapper.createArrayNode();
|
||||
ObjectNode obj = ParsingUtilities.mapper.createObjectNode();
|
||||
obj.put("username", username);
|
||||
obj.put("password", password);
|
||||
array.add(obj);
|
||||
prefStore.put(PREFERENCE_STORE_KEY, array);
|
||||
}
|
||||
|
||||
connection = createNewConnection();
|
||||
try {
|
||||
connection.login(username, password);
|
||||
} catch (LoginFailedException e) {
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore any previously saved connection, from the preferences.
|
||||
*/
|
||||
public void restoreSavedConnection() {
|
||||
ObjectNode savedCredentials = getStoredCredentials();
|
||||
if (savedCredentials != null) {
|
||||
connection = createNewConnection();
|
||||
try {
|
||||
connection.login(savedCredentials.get("username").asText(), savedCredentials.get("password").asText());
|
||||
} catch (LoginFailedException e) {
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectNode getStoredCredentials() {
|
||||
ArrayNode array = (ArrayNode) prefStore.get(PREFERENCE_STORE_KEY);
|
||||
if (array != null && array.size() > 0 && array.get(0) instanceof ObjectNode) {
|
||||
return (ObjectNode) array.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void logout() {
|
||||
prefStore.put(PREFERENCE_STORE_KEY, ParsingUtilities.mapper.createArrayNode());
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.logout();
|
||||
connection = null;
|
||||
} catch (IOException | MediaWikiApiErrorException e) {
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ApiConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
public boolean isLoggedIn() {
|
||||
return connection != null;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
if (connection != null) {
|
||||
return connection.getCurrentUser();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fresh connection object with our
|
||||
* prefered settings.
|
||||
* @return
|
||||
*/
|
||||
protected BasicApiConnection createNewConnection() {
|
||||
BasicApiConnection conn = BasicApiConnection.getWikidataApiConnection();
|
||||
conn.setConnectTimeout(CONNECT_TIMEOUT);
|
||||
conn.setReadTimeout(READ_TIMEOUT);
|
||||
return conn;
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.openrefine.wikidata.editing.ConnectionManager;
|
||||
import org.openrefine.wikidata.commands.ConnectionManager;
|
||||
import org.openrefine.wikidata.editing.EditBatchProcessor;
|
||||
import org.openrefine.wikidata.editing.NewItemLibrary;
|
||||
import org.openrefine.wikidata.schema.WikibaseSchema;
|
||||
|
@ -1,43 +1,466 @@
|
||||
package org.openrefine.wikidata.commands;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import com.google.refine.ProjectManager;
|
||||
import com.google.refine.commands.Command;
|
||||
import com.google.refine.preference.PreferenceStore;
|
||||
import com.google.refine.util.ParsingUtilities;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
import org.wikidata.wdtk.wikibaseapi.BasicApiConnection;
|
||||
import org.wikidata.wdtk.wikibaseapi.LoginFailedException;
|
||||
import org.wikidata.wdtk.wikibaseapi.OAuthApiConnection;
|
||||
import org.wikidata.wdtk.wikibaseapi.apierrors.AssertUserFailedException;
|
||||
import org.wikidata.wdtk.wikibaseapi.apierrors.MediaWikiApiErrorException;
|
||||
|
||||
import com.google.refine.commands.Command;
|
||||
import com.google.refine.util.TestUtils;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.refine.util.TestUtils.assertEqualAsJson;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.openrefine.wikidata.commands.LoginCommand.*;
|
||||
import static org.powermock.api.mockito.PowerMockito.*;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
@PrepareForTest(ConnectionManager.class)
|
||||
public class LoginCommandTest extends CommandTest {
|
||||
|
||||
private static final String username = "my_username";
|
||||
private static final String password = "my_password";
|
||||
|
||||
private static final String consumerToken = "my_consumer_token";
|
||||
private static final String consumerSecret = "my_consumer_secret";
|
||||
private static final String accessToken = "my_access_token";
|
||||
private static final String accessSecret = "my_access_secret";
|
||||
|
||||
private static final Map<String, String> cookieMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
cookieMap.put("GeoIP", "TW:TXG:Taichung:24.15:120.68:v4");
|
||||
cookieMap.put("WMF-Last-Access", "15-Jun-2020");
|
||||
cookieMap.put("WMF-Last-Access-Global", "15-Jun-2020");
|
||||
cookieMap.put("centralauth_Session", "centralauth_Session123");
|
||||
cookieMap.put("centralauth_Token", "centralauth_Token123");
|
||||
cookieMap.put("centralauth_User", username);
|
||||
cookieMap.put("wikidatawikiSession", "wikidatawikiSession123");
|
||||
cookieMap.put("wikidatawikiUserID", "123456");
|
||||
cookieMap.put("wikidatawikiUserName", username);
|
||||
}
|
||||
|
||||
private static final int ONE_YEAR = 60 * 60 * 24 * 365;
|
||||
|
||||
private ArgumentCaptor<Cookie> cookieCaptor;
|
||||
|
||||
// used for mocking singleton
|
||||
Constructor<ConnectionManager> constructor;
|
||||
|
||||
@BeforeClass
|
||||
public void initConstructor() throws NoSuchMethodException {
|
||||
constructor = ConnectionManager.class.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
}
|
||||
|
||||
@BeforeMethod
|
||||
public void SetUp() {
|
||||
public void setUp() throws Exception {
|
||||
command = new LoginCommand();
|
||||
|
||||
// mock the ConnectionManager singleton
|
||||
ConnectionManager manager = constructor.newInstance();
|
||||
mockStatic(ConnectionManager.class);
|
||||
given(ConnectionManager.getInstance()).willReturn(manager);
|
||||
|
||||
when(request.getCookies()).thenReturn(new Cookie[]{});
|
||||
cookieCaptor = ArgumentCaptor.forClass(Cookie.class);
|
||||
doNothing().when(response).addCookie(cookieCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearCredentialsInPreferences() throws Exception {
|
||||
PreferenceStore prefStore = new PreferenceStore();
|
||||
ProjectManager.singleton = mock(ProjectManager.class);
|
||||
when(ProjectManager.singleton.getPreferenceStore()).thenReturn(prefStore);
|
||||
prefStore.put(ConnectionManager.PREFERENCE_STORE_KEY, ParsingUtilities.mapper.createArrayNode());
|
||||
assertNotNull(prefStore.get(ConnectionManager.PREFERENCE_STORE_KEY));
|
||||
constructor.newInstance();
|
||||
assertNull(prefStore.get(ConnectionManager.PREFERENCE_STORE_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCredentials() throws ServletException, IOException {
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
|
||||
command.doPost(request, response);
|
||||
|
||||
assertEquals("{\"logged_in\":false,\"username\":null}", writer.toString());
|
||||
// the first param is the actual one for testng.assertEquals
|
||||
assertEquals(writer.toString(), "{\"logged_in\":false,\"username\":null}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCsrfProtection() throws ServletException, IOException {
|
||||
command.doPost(request, response);
|
||||
TestUtils.assertEqualAsJson("{\"code\":\"error\",\"message\":\"Missing or invalid csrf_token parameter\"}", writer.toString());
|
||||
assertEqualAsJson("{\"code\":\"error\",\"message\":\"Missing or invalid csrf_token parameter\"}", writer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNotCsrfProtected() throws ServletException, IOException {
|
||||
command.doGet(request, response);
|
||||
TestUtils.assertEqualAsJson("{\"logged_in\":false,\"username\":null}", writer.toString());
|
||||
assertEqualAsJson("{\"logged_in\":false,\"username\":null}", writer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernamePasswordLogin() throws Exception {
|
||||
BasicApiConnection connection = mock(BasicApiConnection.class);
|
||||
whenNew(BasicApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
when(connection.getCurrentUser()).thenReturn(username);
|
||||
when(connection.getCookies()).thenReturn(makeResponseCookies());
|
||||
when(connection.getCookies()).thenReturn(makeResponseCookies());
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
when(request.getParameter(USERNAME)).thenReturn(username);
|
||||
when(request.getParameter(PASSWORD)).thenReturn(password);
|
||||
|
||||
command.doPost(request, response);
|
||||
|
||||
verify(connection).login(username, password);
|
||||
assertTrue(ConnectionManager.getInstance().isLoggedIn());
|
||||
assertEqualAsJson("{\"logged_in\":true,\"username\":\"" + username + "\"}", writer.toString());
|
||||
|
||||
Map<String, Cookie> cookies = getCookieMap(cookieCaptor.getAllValues());
|
||||
assertEquals(cookies.size(), 5);
|
||||
assertCookieEquals(cookies.get(WIKIBASE_USERNAME_COOKIE_KEY), "", 0);
|
||||
assertCookieEquals(cookies.get(CONSUMER_TOKEN), "", 0);
|
||||
assertCookieEquals(cookies.get(CONSUMER_SECRET), "", 0);
|
||||
assertCookieEquals(cookies.get(ACCESS_TOKEN), "", 0);
|
||||
assertCookieEquals(cookies.get(ACCESS_SECRET), "", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernamePasswordLoginRememberCredentials() throws Exception {
|
||||
BasicApiConnection connection = mock(BasicApiConnection.class);
|
||||
whenNew(BasicApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
when(connection.getCurrentUser()).thenReturn(username);
|
||||
when(connection.getCookies()).thenReturn(makeResponseCookies());
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
when(request.getParameter("remember-credentials")).thenReturn("on");
|
||||
when(request.getParameter(USERNAME)).thenReturn(username);
|
||||
when(request.getParameter(PASSWORD)).thenReturn(password);
|
||||
|
||||
command.doPost(request, response);
|
||||
|
||||
verify(connection).login(username, password);
|
||||
assertTrue(ConnectionManager.getInstance().isLoggedIn());
|
||||
assertEqualAsJson("{\"logged_in\":true,\"username\":\"" + username + "\"}", writer.toString());
|
||||
|
||||
Map<String, Cookie> cookies = getCookieMap(cookieCaptor.getAllValues());
|
||||
cookieMap.forEach((key, value) -> assertCookieEquals(cookies.get(WIKIDATA_COOKIE_PREFIX + key), value, ONE_YEAR));
|
||||
assertCookieEquals(cookies.get(WIKIBASE_USERNAME_COOKIE_KEY), username, ONE_YEAR);
|
||||
assertCookieEquals(cookies.get(CONSUMER_TOKEN), "", 0);
|
||||
assertCookieEquals(cookies.get(CONSUMER_SECRET), "", 0);
|
||||
assertCookieEquals(cookies.get(ACCESS_TOKEN), "", 0);
|
||||
assertCookieEquals(cookies.get(ACCESS_SECRET), "", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernamePasswordLoginWithCookies() throws Exception {
|
||||
BasicApiConnection connection = mock(BasicApiConnection.class);
|
||||
given(ConnectionManager.convertToBasicApiConnection(anyMap())).willReturn(connection);
|
||||
when(connection.getCurrentUser()).thenReturn(username);
|
||||
when(connection.getCookies()).thenReturn(makeResponseCookies());
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
when(request.getCookies()).thenReturn(makeRequestCookies());
|
||||
|
||||
command.doPost(request, response);
|
||||
|
||||
verify(connection).checkCredentials();
|
||||
assertTrue(ConnectionManager.getInstance().isLoggedIn());
|
||||
assertEqualAsJson("{\"logged_in\":true,\"username\":\"" + username + "\"}", writer.toString());
|
||||
|
||||
Map<String, Cookie> cookies = getCookieMap(cookieCaptor.getAllValues());
|
||||
assertEquals(cookies.size(), 4);
|
||||
assertCookieEquals(cookies.get(CONSUMER_TOKEN), "", 0);
|
||||
assertCookieEquals(cookies.get(CONSUMER_SECRET), "", 0);
|
||||
assertCookieEquals(cookies.get(ACCESS_TOKEN), "", 0);
|
||||
assertCookieEquals(cookies.get(ACCESS_SECRET), "", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerOnlyConsumerLogin() throws Exception {
|
||||
OAuthApiConnection connection = mock(OAuthApiConnection.class);
|
||||
whenNew(OAuthApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
when(connection.getCurrentUser()).thenReturn(username);
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
when(request.getParameter(CONSUMER_TOKEN)).thenReturn(consumerToken);
|
||||
when(request.getParameter(CONSUMER_SECRET)).thenReturn(consumerSecret);
|
||||
when(request.getParameter(ACCESS_TOKEN)).thenReturn(accessToken);
|
||||
when(request.getParameter(ACCESS_SECRET)).thenReturn(accessSecret);
|
||||
|
||||
command.doPost(request, response);
|
||||
|
||||
assertTrue(ConnectionManager.getInstance().isLoggedIn());
|
||||
assertEqualAsJson("{\"logged_in\":true,\"username\":\"" + username + "\"}", writer.toString());
|
||||
|
||||
Map<String, Cookie> cookies = getCookieMap(cookieCaptor.getAllValues());
|
||||
assertEquals(cookies.size(), 5);
|
||||
assertCookieEquals(cookies.get(WIKIBASE_USERNAME_COOKIE_KEY), "", 0);
|
||||
assertCookieEquals(cookies.get(CONSUMER_TOKEN), "", 0);
|
||||
assertCookieEquals(cookies.get(CONSUMER_SECRET), "", 0);
|
||||
assertCookieEquals(cookies.get(ACCESS_TOKEN), "", 0);
|
||||
assertCookieEquals(cookies.get(ACCESS_SECRET), "", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerOnlyConsumerLoginRememberCredentials() throws Exception {
|
||||
OAuthApiConnection connection = mock(OAuthApiConnection.class);
|
||||
whenNew(OAuthApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
when(connection.getCurrentUser()).thenReturn(username);
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
when(request.getParameter("remember-credentials")).thenReturn("on");
|
||||
when(request.getParameter(CONSUMER_TOKEN)).thenReturn(consumerToken);
|
||||
when(request.getParameter(CONSUMER_SECRET)).thenReturn(consumerSecret);
|
||||
when(request.getParameter(ACCESS_TOKEN)).thenReturn(accessToken);
|
||||
when(request.getParameter(ACCESS_SECRET)).thenReturn(accessSecret);
|
||||
when(request.getCookies()).thenReturn(makeRequestCookies());
|
||||
|
||||
command.doPost(request, response);
|
||||
|
||||
assertEqualAsJson("{\"logged_in\":true,\"username\":\"" + username + "\"}", writer.toString());
|
||||
|
||||
Map<String, Cookie> cookies = getCookieMap(cookieCaptor.getAllValues());
|
||||
// If logging in with owner-only consumer,
|
||||
// cookies for the username/password login should be cleared.
|
||||
cookieMap.forEach((key, value) -> assertCookieEquals(cookies.get(WIKIDATA_COOKIE_PREFIX + key), "", 0));
|
||||
assertCookieEquals(cookies.get(WIKIBASE_USERNAME_COOKIE_KEY), "", 0);
|
||||
assertCookieEquals(cookies.get(CONSUMER_TOKEN), consumerToken, ONE_YEAR);
|
||||
assertCookieEquals(cookies.get(CONSUMER_SECRET), consumerSecret, ONE_YEAR);
|
||||
assertCookieEquals(cookies.get(ACCESS_TOKEN), accessToken, ONE_YEAR);
|
||||
assertCookieEquals(cookies.get(ACCESS_SECRET), accessSecret, ONE_YEAR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieEncoding() throws Exception {
|
||||
OAuthApiConnection connection = mock(OAuthApiConnection.class);
|
||||
whenNew(OAuthApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
when(request.getParameter("remember-credentials")).thenReturn("on");
|
||||
when(request.getParameter(CONSUMER_TOKEN)).thenReturn("malformed consumer token \r\n %?");
|
||||
when(request.getParameter(CONSUMER_SECRET)).thenReturn(consumerSecret);
|
||||
when(request.getParameter(ACCESS_TOKEN)).thenReturn(accessToken);
|
||||
when(request.getParameter(ACCESS_SECRET)).thenReturn(accessSecret);
|
||||
when(request.getCookies()).thenReturn(makeRequestCookies());
|
||||
|
||||
command.doPost(request, response);
|
||||
|
||||
Map<String, Cookie> cookies = getCookieMap(cookieCaptor.getAllValues());
|
||||
assertNotEquals(cookies.get(CONSUMER_TOKEN).getValue(), "malformed consumer token \r\n %?");
|
||||
assertEquals(cookies.get(CONSUMER_TOKEN).getValue(), "malformed+consumer+token+%0D%0A+%25%3F");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerOnlyConsumerLoginWithCookies() throws Exception {
|
||||
OAuthApiConnection connection = mock(OAuthApiConnection.class);
|
||||
whenNew(OAuthApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
when(connection.getCurrentUser()).thenReturn(username);
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
Cookie consumerTokenCookie = new Cookie(CONSUMER_TOKEN, consumerToken);
|
||||
Cookie consumerSecretCookie = new Cookie(CONSUMER_SECRET, consumerSecret);
|
||||
Cookie accessTokenCookie = new Cookie(ACCESS_TOKEN, accessToken);
|
||||
Cookie accessSecretCookie = new Cookie(ACCESS_SECRET, accessSecret);
|
||||
when(request.getCookies()).thenReturn(new Cookie[]{consumerTokenCookie, consumerSecretCookie, accessTokenCookie, accessSecretCookie});
|
||||
command.doPost(request, response);
|
||||
|
||||
assertTrue(ConnectionManager.getInstance().isLoggedIn());
|
||||
assertEqualAsJson("{\"logged_in\":true,\"username\":\"" + username + "\"}", writer.toString());
|
||||
|
||||
Map<String, Cookie> cookies = getCookieMap(cookieCaptor.getAllValues());
|
||||
assertEquals(cookies.size(), 5);
|
||||
assertCookieEquals(cookies.get(WIKIBASE_USERNAME_COOKIE_KEY), "", 0);
|
||||
assertCookieEquals(cookies.get(CONSUMER_TOKEN), consumerToken, ONE_YEAR);
|
||||
assertCookieEquals(cookies.get(CONSUMER_SECRET), consumerSecret, ONE_YEAR);
|
||||
assertCookieEquals(cookies.get(ACCESS_TOKEN), accessToken, ONE_YEAR);
|
||||
assertCookieEquals(cookies.get(ACCESS_SECRET), accessSecret, ONE_YEAR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCookieDecoding() throws Exception {
|
||||
ConnectionManager manager = mock(ConnectionManager.class);
|
||||
given(ConnectionManager.getInstance()).willReturn(manager);
|
||||
|
||||
OAuthApiConnection connection = mock(OAuthApiConnection.class);
|
||||
whenNew(OAuthApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
when(connection.getCurrentUser()).thenReturn(username);
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
Cookie consumerTokenCookie = new Cookie(CONSUMER_TOKEN, "malformed+consumer+token+%0D%0A+%25%3F");
|
||||
Cookie consumerSecretCookie = new Cookie(CONSUMER_SECRET, consumerSecret);
|
||||
Cookie accessTokenCookie = new Cookie(ACCESS_TOKEN, accessToken);
|
||||
Cookie accessSecretCookie = new Cookie(ACCESS_SECRET, accessSecret);
|
||||
when(request.getCookies()).thenReturn(new Cookie[]{consumerTokenCookie, consumerSecretCookie, accessTokenCookie, accessSecretCookie});
|
||||
|
||||
command.doPost(request, response);
|
||||
|
||||
verify(manager).login("malformed consumer token \r\n %?", consumerSecret, accessToken, accessSecret);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogout() throws Exception {
|
||||
BasicApiConnection connection = mock(BasicApiConnection.class);
|
||||
whenNew(BasicApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
when(connection.getCurrentUser()).thenReturn(username);
|
||||
when(connection.getCookies()).thenReturn(makeResponseCookies());
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
when(request.getParameter(USERNAME)).thenReturn(username);
|
||||
when(request.getParameter(PASSWORD)).thenReturn(password);
|
||||
|
||||
// login first
|
||||
command.doPost(request, response);
|
||||
|
||||
int loginCookiesSize = cookieCaptor.getAllValues().size();
|
||||
|
||||
assertTrue(ConnectionManager.getInstance().isLoggedIn());
|
||||
assertEqualAsJson("{\"logged_in\":true,\"username\":\"" + username + "\"}", writer.toString());
|
||||
|
||||
// logout
|
||||
when(request.getParameter("logout")).thenReturn("true");
|
||||
when(request.getCookies()).thenReturn(makeRequestCookies()); // will be cleared
|
||||
StringWriter logoutWriter = new StringWriter();
|
||||
when(response.getWriter()).thenReturn(new PrintWriter(logoutWriter));
|
||||
|
||||
command.doPost(request, response);
|
||||
|
||||
assertFalse(ConnectionManager.getInstance().isLoggedIn());
|
||||
assertEqualAsJson("{\"logged_in\":false,\"username\":null}", logoutWriter.toString());
|
||||
|
||||
Map<String, Cookie> cookies = getCookieMap(cookieCaptor.getAllValues().subList(loginCookiesSize, cookieCaptor.getAllValues().size()));
|
||||
cookieMap.forEach((key, value) -> assertCookieEquals(cookies.get(WIKIDATA_COOKIE_PREFIX + key), "", 0));
|
||||
assertCookieEquals(cookies.get(WIKIBASE_USERNAME_COOKIE_KEY), "", 0);
|
||||
assertCookieEquals(cookies.get(CONSUMER_TOKEN), "", 0);
|
||||
assertCookieEquals(cookies.get(CONSUMER_SECRET), "", 0);
|
||||
assertCookieEquals(cookies.get(ACCESS_TOKEN), "", 0);
|
||||
assertCookieEquals(cookies.get(ACCESS_SECRET), "", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernamePasswordLoginFailed() throws Exception {
|
||||
BasicApiConnection connection = mock(BasicApiConnection.class);
|
||||
whenNew(BasicApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
doThrow(new LoginFailedException("login failed")).when(connection).login(username, password);
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
// we don't check the username/password here
|
||||
when(request.getParameter(USERNAME)).thenReturn(username);
|
||||
when(request.getParameter(PASSWORD)).thenReturn(password);
|
||||
|
||||
// login first
|
||||
command.doPost(request, response);
|
||||
|
||||
verify(connection).login(username, password);
|
||||
assertFalse(ConnectionManager.getInstance().isLoggedIn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernamePasswordWithCookiesLoginFailed() throws Exception {
|
||||
BasicApiConnection connection = mock(BasicApiConnection.class);
|
||||
given(ConnectionManager.convertToBasicApiConnection(anyMap())).willReturn(connection);
|
||||
doThrow(new AssertUserFailedException("assert user login failed")).when(connection).checkCredentials();
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
// we don't check the username/password here
|
||||
when(request.getCookies()).thenReturn(makeRequestCookies());
|
||||
|
||||
// login first
|
||||
command.doPost(request, response);
|
||||
|
||||
verify(connection).checkCredentials();
|
||||
assertFalse(ConnectionManager.getInstance().isLoggedIn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerOnlyConsumerLoginFailed() throws Exception {
|
||||
OAuthApiConnection connection = mock(OAuthApiConnection.class);
|
||||
whenNew(OAuthApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
doThrow(new AssertUserFailedException("assert user login failed")).when(connection).checkCredentials();
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
when(request.getParameter(CONSUMER_TOKEN)).thenReturn(consumerToken);
|
||||
when(request.getParameter(CONSUMER_SECRET)).thenReturn(consumerSecret);
|
||||
when(request.getParameter(ACCESS_TOKEN)).thenReturn(accessToken);
|
||||
when(request.getParameter(ACCESS_SECRET)).thenReturn(accessSecret);
|
||||
|
||||
command.doPost(request, response);
|
||||
|
||||
verify(connection).checkCredentials();
|
||||
assertFalse(connection.isLoggedIn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogoutFailed() throws Exception {
|
||||
BasicApiConnection connection = mock(BasicApiConnection.class);
|
||||
whenNew(BasicApiConnection.class).withAnyArguments().thenReturn(connection);
|
||||
when(connection.getCurrentUser()).thenReturn(username);
|
||||
|
||||
when(request.getParameter("csrf_token")).thenReturn(Command.csrfFactory.getFreshToken());
|
||||
when(request.getParameter(USERNAME)).thenReturn(username);
|
||||
when(request.getParameter(PASSWORD)).thenReturn(password);
|
||||
|
||||
// login first
|
||||
command.doPost(request, response);
|
||||
|
||||
assertTrue(ConnectionManager.getInstance().isLoggedIn());
|
||||
|
||||
// logout
|
||||
when(request.getParameter("logout")).thenReturn("true");
|
||||
doThrow(new MediaWikiApiErrorException("", "")).when(connection).logout();
|
||||
command.doPost(request, response);
|
||||
|
||||
// still logged in
|
||||
assertTrue(ConnectionManager.getInstance().isLoggedIn());
|
||||
}
|
||||
|
||||
private static Cookie[] makeRequestCookies() {
|
||||
List<Cookie> cookies = new ArrayList<>();
|
||||
cookieMap.forEach((key, value) -> cookies.add(new Cookie(WIKIDATA_COOKIE_PREFIX + key, value)));
|
||||
cookies.add(new Cookie(WIKIBASE_USERNAME_COOKIE_KEY, username));
|
||||
return cookies.toArray(new Cookie[0]);
|
||||
}
|
||||
|
||||
private static List<HttpCookie> makeResponseCookies() {
|
||||
List<HttpCookie> cookies = new ArrayList<>();
|
||||
cookieMap.forEach((key, value) -> cookies.add(new HttpCookie(key, value)));
|
||||
return cookies;
|
||||
}
|
||||
|
||||
private static void assertCookieEquals(Cookie cookie, String expectedValue, int expectedMaxAge) {
|
||||
try {
|
||||
assertEquals(getCookieValue(cookie), expectedValue);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
assertEquals(cookie.getMaxAge(), expectedMaxAge);
|
||||
assertEquals(cookie.getPath(), "/");
|
||||
}
|
||||
|
||||
private static Map<String, Cookie> getCookieMap(List<Cookie> cookies) {
|
||||
Map<String, Cookie> map = new HashMap<>();
|
||||
cookies.forEach(cookie -> map.put(cookie.getName(), cookie));
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
14
pom.xml
14
pom.xml
@ -216,5 +216,19 @@
|
||||
-->
|
||||
</dependencies>
|
||||
|
||||
<!-- enabled to access our snapshots of Wikidata-Toolkit -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user