Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upload #108

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9c44029
Oauth 2
zexigong May 29, 2023
ca13b36
basic login
zexigong May 31, 2023
2c6a526
Show username
zexigong Jun 1, 2023
a38bd95
finish login/logout with drop down
zexigong Jun 1, 2023
0f982c2
return to previous page after login
zexigong Jun 2, 2023
b81edd6
set icons and wait page
zexigong Jun 9, 2023
63475c0
enable image action menu; add popup
zexigong Jun 20, 2023
e79679d
disable image remove menu; clean code
zexigong Jun 20, 2023
babb16c
show popup in imagegrid; convert text to wiki templates
zexigong Jun 23, 2023
a911fff
add upload
zexigong Jul 18, 2023
1f48030
update with new Oauth app, add UI and API call for upload
zexigong Aug 4, 2023
429893a
new Oauth app support upload and edit
zexigong Aug 7, 2023
e1caceb
update popup
zexigong Aug 23, 2023
2c597ca
add comment and item pull down
zexigong Aug 28, 2023
5718231
change request params with finnaId
zexigong Aug 31, 2023
e0c5504
add comment
zexigong Sep 1, 2023
1478d2f
Delete Oauth.js
zexigong Sep 1, 2023
5825b94
Wait until login response is handled before redirecting
tuukka Sep 4, 2023
47d6ddc
add translation
zexigong Sep 5, 2023
d024645
Merge branch 'upload' of https://github.com/zexigong/wikidocumentarie…
zexigong Sep 5, 2023
0edd3f7
Fix popup progression by removing template syntax error
tuukka Sep 5, 2023
ce44053
Remove an unnecessary debug function
tuukka Sep 5, 2023
d6b6d76
Produce prettier wikitext by including linebreaks
tuukka Sep 5, 2023
4f4f146
Fix logic to include the year always when we have one
tuukka Sep 5, 2023
9d76d5e
Add the FinnaReview template to copyrights from Finna
tuukka Sep 5, 2023
d766d9e
Support OAUTH_CLIENT{_ID,_SECRET} environment variables
tuukka Sep 5, 2023
1a1212f
Add local copy of pkce-challenge 4.0.1 from NPM
tuukka Sep 5, 2023
d424498
Fix pkce-challenge to work in our build system
tuukka Sep 5, 2023
fc5add0
Add OAuth code challenge for our non-confidential app
tuukka Sep 5, 2023
0ea9a31
Update en.json
susannaanas Sep 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion config/prod.env.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
process = require('process');
module.exports = {
NODE_ENV: '"production"',
API_URL: JSON.stringify(process.env.API_URL)
API_URL: JSON.stringify(process.env.API_URL),
OAUTH_CLIENT_ID: JSON.stringify(process.env.OAUTH_CLIENT_ID),
OAUTH_CLIENT_SECRET: JSON.stringify(process.env.OAUTH_CLIENT_SECRET),
};
29 changes: 26 additions & 3 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ a:hover {
.toolbar {
display: flex;
color: #333;
padding: 0 20px;
padding-left: 20px;
min-height: 45px; /* Normal height, but line wrap can grow this */
align-items: flex-start; /* We want multiple lines to align to the top */
line-height: 1.2;
Expand All @@ -187,8 +187,8 @@ a:hover {
justify-content: center;
cursor: pointer;
width: 45px;
padding-top: 9px; /* To adjust baseline to a good position */
padding-bottom: 6px; /* For visual symmetry */
height: 45px;
align-items: center;
}

.toolbar-item-a {
Expand Down Expand Up @@ -717,6 +717,19 @@ i.wikiglyph {
-webkit-column-break-inside: avoid;
}

.upload-button {
padding: 10px 15px;
background-color: var(--main-red);
color: white;
font-weight: 600;
border-radius: 3px;
white-space: nowrap;
}

a:hover .upload-button {
background-color: var(--main-orange);
}

.data-select {
display: block;
background: var(--main-red);
Expand All @@ -729,6 +742,16 @@ i.wikiglyph {
/* transition: background 80ms ease-in, color 80ms ease-in; */
}

.data-select a {
color:white;
font-size: 0.7em;
}

.data-select a:hover {
box-shadow: none;
text-decoration: underline;
}

.data-button {
display: inline-block;
position: absolute;
Expand Down
16 changes: 8 additions & 8 deletions src/components/ImageGrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
<div class="thumb-credit">{{ getCredits(item) }}</div>
<img class="icon" :src="getIcon(item)" align="right">
</div>
<div class="thumb-image-header">
<div class="left-align">
<!-- <ImagesActionMenu v-bind:element="item"></ImagesActionMenu> -->
<div class="thumb-image-header">
<div class="left-align" @click.stop>
<ImagesActionMenu v-bind:element="item"></ImagesActionMenu>
<div
v-if="item.geoLocations != undefined && item.geoLocations.length > 0"
class="header-item"
Expand All @@ -36,7 +36,7 @@
<i class="wikiglyph wikiglyph-new-window thumb-image-glyph"></i>
</a>
</div>
<!--ImagesRemoveMenu></ImagesRemoveMenu-->
<!-- <ImagesRemoveMenu></ImagesRemoveMenu> -->
</div>
</div>
</div>
Expand All @@ -48,8 +48,8 @@

<script>
import ImageViewer from "@/components/image_viewer/ImageViewer";
// import ImagesActionMenu from '@/components/menu/ImagesActionMenu'
// import ImagesRemoveMenu from '@/components/menu/ImagesRemoveMenu'
import ImagesActionMenu from '@/components/menu/ImagesActionMenu';
// import ImagesRemoveMenu from '@/components/menu/ImagesRemoveMenu';

export default {
name: "ImageGrid",
Expand All @@ -62,8 +62,8 @@ export default {
}
},
components: {
ImageViewer
// ImagesActionMenu,
ImageViewer,
ImagesActionMenu,
// ImagesRemoveMenu,
},
methods: {
Expand Down
11 changes: 9 additions & 2 deletions src/components/MainPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
<a class="main-button" v-on:click="goToLandingPage">{{ landingPageName }}</a>
<TopicSearchBox class="topic-search-box"></TopicSearchBox>
<UILanguageMenu class="language-menu"></UILanguageMenu>
<LoginButton v-if="notLogIn"></LoginButton>
<UserProfile v-else></UserProfile>
</div>
<component
v-bind:is="currentTabComponentName"
Expand All @@ -37,6 +39,8 @@ import TopicPage from '@/components/topic_page/HomePage'
import WaitPage from '@/components/WaitPage'
import TopicSearchBox from '@/components/TopicSearchBox'
import UILanguageMenu from '@/components/menu/UILanguageMenu'
import LoginButton from '@/components/authentication/Login';
import UserProfile from '@/components/authentication/UserProfile.vue';

export default {
name: 'MainPage',
Expand All @@ -52,6 +56,7 @@ export default {
],
WIKI: WIKI,
landingPageName: "Wikidocumentaries",
notLogIn: localStorage.getItem("username") === null,
}
},
computed: {
Expand All @@ -63,7 +68,9 @@ export default {
TopicPage,
WaitPage,
UILanguageMenu,
TopicSearchBox
TopicSearchBox,
LoginButton,
UserProfile
},
beforeRouteEnter (to, from, next) {
//console.log(to);
Expand Down Expand Up @@ -152,7 +159,7 @@ a.main-button:hover {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
padding-left: 20px;
}

/*. main-toolbar-buttons {
Expand Down
51 changes: 51 additions & 0 deletions src/components/authentication/Login.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!-- The Login component is for users to initiate the login process.
It presents a "Login" button within the toolbar menu, which, when clicked, redirects the user to the
authentication page. After successful login, the user is redirected back to the previous page. -->
<template>
<ToolbarMenu
icon="wikiglyph-user-inactive"
:tooltip="$t('login.loginMenu.tooltip')"
:translateItems="false"
:items="[{id:'login', text:itemtext}]"
@doMenuItemAction="getCode"
>
<div slot="menu-title">{{ $t('login.loginMenu.title') }}</div>
</ToolbarMenu>
</template>

<script>
import pkceChallenge from "@/pkce-challenge";

import ToolbarMenu from '@/components/menu/ToolbarMenu'
export default {
name: 'LoginButton',
data(){
return{
// This is a public app with upload and edit grant
CLIENT_ID : process.env.OAUTH_CLIENT_ID || "f2aa70edfeb48a0eb08614c69b9148b4",
itemtext: this.$t('login.loginMenu.item')
}
},
components: {
ToolbarMenu,
},
methods: {
async getCode() {
localStorage.setItem('previouspage', window.location.href);

const challenge = await pkceChallenge();
localStorage.setItem('codeVerifier', challenge.code_verifier);

const params = new URLSearchParams();
params.append("client_id", this.CLIENT_ID);
params.append("response_type", "code");
params.append("code_challenge", challenge.code_challenge);
params.append("code_challenge_method", "S256");

// Redirect the browser to the OAuth 2 login page
const url = "https://meta.wikimedia.org/w/rest.php/oauth2/authorize?" + params;
window.location.href = url;
},
}
}
</script>
96 changes: 96 additions & 0 deletions src/components/authentication/LoginSuccess.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<!-- The LoginSuccess component manages the post-login process. It is responsible for acquiring
an access token, retrieving user profile information, and redirecting the user back to the previous page.
This component also provides a loading animation, which is modified from wait-page, with a success message. -->
<template>
<div class="wait-page">
<div class="bars">
<div class="yellow"></div>
<div class="orange"></div>
<div class="red"></div>
<div class="purple"></div>
<div class="turquoise"></div>
<div class="green"></div>
</div>
<div class="wait">
<div class="lds-heart">
<div></div>
</div>
<div class="message">{{ $t('login.loginSuccess') }}</div>
</div>
</div>
</template>

<script>
import axios from "axios";
export default {
name: "LoginSuccess",
data() {
return {
CLIENT_ID: process.env.OAUTH_CLIENT_ID || "f2aa70edfeb48a0eb08614c69b9148b4",
CLIENT_SECRET: process.env.OAUTH_CLIENT_SECRET || "48830e519cfc29240c9291a7f301e437d0355958",
profileUrl: "https://meta.wikimedia.org/w/rest.php/oauth2/resource/profile",
};
},
methods: {

async getAccessToken() {
const code = this.$route.query.code;
const params = new URLSearchParams();
params.append("grant_type", "authorization_code");
params.append("code", code);
params.append("client_id", this.CLIENT_ID);
params.append("client_secret", this.CLIENT_SECRET);
params.append("code_verifier", localStorage.codeVerifier);
console.log(params);
const fetchDataRes = await axios.request({
url: "/w/rest.php/oauth2/access_token",
method: "post",
baseURL: "https://meta.wikimedia.org",
data: params
});
console.log(fetchDataRes.data.access_token);
localStorage.setItem("access_token", fetchDataRes.data.access_token);
localStorage.removeItem('codeVerifier');
},
async getUserProfile() {
let response = await fetch(this.profileUrl, {
headers: {
Authorization: "Bearer " + localStorage.getItem("access_token")
}
});
const body = await response.json();
localStorage.setItem("username", body.username);
},
returnToPage(){
let url = localStorage.getItem('previouspage');
localStorage.removeItem('previouspage');
window.location.href = url;
},
},

mounted: async function() {
await this.getAccessToken();
await this.getUserProfile();
this.returnToPage();
}
};
</script>

<style scoped>
.wait {
padding: 20px;
display: flex;
align-items: center;
}

.message {
padding-left: 20px;
}
.bars {
flex: 1 0 100%;
height: 18px;
display: flex;
flex-wrap: nowrap;
}
</style>

46 changes: 46 additions & 0 deletions src/components/authentication/UserProfile.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!-- This component represents a user profile element in a toolbar menu.
It displays the user's name and provides an option to log out. -->
<template>
<div>
<ToolbarMenu
icon="wikiglyph-user-active"
:tooltip="$t('login.loginMenu.showProfile')"
:translateItems="false"
:items="[{id:'logout', text: itemtext }]"
@doMenuItemAction="logOut"
>
<div slot="menu-title">{{name}}</div>
</ToolbarMenu>
</div>
</template>


<script>
import ToolbarMenu from '@/components/menu/ToolbarMenu';

export default {
name: 'UserProfile',
data() {
return{
name: '',
itemtext: this.$t('login.loginMenu.logout')
};

},
mounted() {
if (localStorage.username) {
this.name = localStorage.username;
}
},
components: {
ToolbarMenu,
},
methods: {
logOut (){
localStorage.removeItem('access_token');
localStorage.removeItem('username');
location. reload();
},
}
}
</script>
Loading