2020-10-05 20:36:03 +03:00
Vue . use ( VueMaterial . default ) ;
const getCreatePostError = ( json ) => {
switch ( json . message ) {
case 'ERROR_REQUEST_INVALID_DATA' : {
switch ( json . errors [ 0 ] . param ) {
case 'title' : {
return 'Invalid title. Must be between 3 and 32 characters.' ;
}
case 'body' : {
return 'Invalid content. Must be between 3 and 1000 characters' ;
}
case 'category' : {
return 'Invalid category. Something went wrong.' ;
}
default : {
return 'Invalid value sent to server. Something went wrong.' ;
}
}
}
case 'ERROR_CATEGORY_NOT_FOUND' : {
return 'The category you tried to post to no longer exists.' ;
}
case 'ERROR_ACCESS_DENIED' : {
return 'You are not allowed to perform this action.'
}
default : {
return 'Unknown error. Something went wrong.' ;
}
}
}
const getCreateCategoryError = ( json ) => {
switch ( json . message ) {
case 'ERROR_REQUEST_INVALID_DATA' : {
switch ( json . errors [ 0 ] . param ) {
case 'title' : {
return 'Invalid title. Title must be between 3 and 32 characters.' ;
}
}
}
case 'ERROR_ACCESS_DENIED' : {
return 'You are not allowed to perform this action.'
}
default : {
return 'Unknown error. Something went wrong.' ;
}
}
}
2020-11-16 21:16:25 +02:00
class GatewayConnection {
constructor ( ) {
this . isConnected = false ;
this . socket = null ;
2020-11-16 21:33:03 +02:00
// TODO: set up proper event listening and such, not this dumb crap
this . onDisconnect = ( ) => { }
this . onConnect = ( ) => { }
2020-11-16 21:16:25 +02:00
}
}
GatewayConnection . prototype . connect = function ( token ) {
console . log ( '[*] [gateway] [handshake] Trying to connect to gateway' ) ;
this . socket = io ( '/gateway' , {
query : {
token
} ,
transports : [ 'websocket' ]
} ) ;
this . socket . on ( 'hello' , ( ) => {
console . log ( '[*] [gateway] [handshake] Got hello from server, sending yoo...' ) ;
this . socket . emit ( 'yoo' ) ;
2020-11-16 21:33:03 +02:00
this . onConnect ( 'CONNECT_RECEIVED_HELLO' ) ;
2020-11-16 21:16:25 +02:00
} ) ;
this . socket . on ( 'error' , ( e ) => {
console . log ( '[E] [gateway] Gateway error' , e ) ;
this . isConnected = false ;
2020-11-16 21:33:03 +02:00
this . onDisconnect ( 'DISCONNECT_ERR' , e ) ;
2020-11-16 21:16:25 +02:00
} ) ;
this . socket . on ( 'disconnectNotification' , ( e ) => {
console . log ( '[E] [gateway] Received disconnect notfication' , e ) ;
this . isConnected = false ;
2020-11-16 21:33:03 +02:00
this . onDisconnect ( 'DISCONNECT_NOTIF' , e ) ;
2020-11-16 21:16:25 +02:00
} ) ;
this . socket . on ( 'disconnect' , ( e ) => {
console . log ( '[E] [gateway] Disconnected from gateway: ' , e ) ;
this . isConnected = false ;
2020-11-16 21:33:03 +02:00
this . onDisconnect ( 'DISCONNECT' , e ) ;
2020-11-16 21:16:25 +02:00
} ) ;
} ;
2020-10-05 20:36:03 +03:00
const app = new Vue ( {
el : '#app' ,
data : {
showSnackbarNotification : false ,
snackbarNotification : '' ,
snackbarNotificationDuration : 999999 ,
snackbarButtonText : 'Ok' ,
loggedInUser : { } ,
showApp : false ,
menuVisible : false ,
selection : {
category : {
title : '' ,
browsing : false ,
_id : undefined ,
isCategory : false
} ,
posts : [ ]
} ,
cardButtons : [ ] ,
dialog : {
show : {
createPost : false ,
createCategory : false
} ,
text : {
createPost : {
title : '' ,
body : ''
} ,
createCategory : {
title : ''
}
}
} ,
viewingProfile : {
show : false ,
_id : '' ,
username : '' ,
role : ''
2020-11-16 21:16:25 +02:00
} ,
gateway : new GatewayConnection ( )
2020-10-05 20:36:03 +03:00
} ,
mounted : async function ( ) {
const res = await fetch ( ` ${ window . location . origin } /api/v1/users/current/info ` , {
method : 'GET' ,
headers : {
'Accept' : 'application/json' ,
} ,
credentials : 'include'
} ) ;
if ( res . status === 200 ) {
const json = await res . json ( ) ;
if ( json . user . permissionLevel >= 1 ) {
this . loggedInUser = json . user ;
this . showApp = true ;
2020-11-16 21:16:25 +02:00
this . performGatewayConnection ( ) ;
2020-10-05 20:36:03 +03:00
this . browseCategories ( ) ;
} else {
this . showApp = false ;
this . snackbarEditButton ( 'Manage' , ( ) => {
window . location . href = ` ${ window . location . origin } /auth.html ` ;
this . resetSnackbarButton ( ) ;
this . showSnackbarNotification = false ;
} ) ;
this . notification ( 'Your account does not have the required permissions to enter this page' ) ;
}
} else {
this . showApp = false ;
this . snackbarEditButton ( 'Manage' , ( ) => {
window . location . href = ` ${ window . location . origin } /auth.html ` ;
this . resetSnackbarButton ( ) ;
this . showSnackbarNotification = false ;
} ) ;
this . notification ( 'You are not logged in or your session is invalid' ) ;
}
} ,
methods : {
navigateToAccountManager ( ) {
window . location . href = ` ${ window . location . origin } /auth.html ` ;
} ,
snackbarButtonAction : function ( ) {
this . showSnackbarNotification = false ;
} ,
snackbarButtonClick : function ( ) {
this . snackbarButtonAction ( ) ;
} ,
snackbarEditButton : function ( buttonText = "Ok" , action ) {
this . snackbarButtonText = buttonText ;
this . snackbarButtonAction = action ;
} ,
resetSnackbarButton : function ( ) {
this . snackbarButtonText = 'Ok' ;
this . snackbarButtonAction = ( ) => {
this . showSnackbarNotification = false ;
} ;
} ,
notification : function ( text ) {
this . snackbarNotification = text ;
this . showSnackbarNotification = true ;
} ,
2020-11-16 21:16:25 +02:00
performGatewayConnection : function ( ) {
// TODO: again, the thing im doing with the token is not very secure, since its being sent by the current user info endpoint and is also being send through query parameters
2020-11-16 21:33:03 +02:00
this . gateway . onDisconnect = ( e ) => {
this . resetSnackbarButton ( ) ;
this . notification ( 'ERROR: You have been disconnected from the gateway. Realtime features such as chat will not work and unexpected errors may occur.' ) ;
} ;
2020-11-16 21:16:25 +02:00
this . gateway . connect ( this . loggedInUser . token ) ;
} ,
2020-10-05 20:36:03 +03:00
button : function ( text , click ) {
this . cardButtons . push ( { text , click } ) ;
} ,
refresh : function ( ) {
if ( this . selection . category . title === 'categories' && this . selection . category . isCategory === false ) {
this . browseCategories ( ) ;
} else {
this . browse ( this . selection . category ) ;
}
} ,
viewProfile : async function ( id ) {
// TODO: this just returns the username for now
const res = await fetch ( ` ${ window . location . origin } /api/v1/users/user/ ${ id } /info ` , {
method : 'GET' ,
headers : {
'Accept' : 'application/json' ,
} ,
credentials : 'include'
} ) ;
if ( res . status === 200 ) {
const json = await res . json ( ) ;
this . viewingProfile . username = json . user . username ;
this . viewingProfile . _id = json . user . _id ;
this . viewingProfile . role = json . user . role ;
this . viewingProfile . show = true ;
} else {
this . resetSnackbarButton ( ) ;
this . notification ( 'Failed to fetch user data' ) ;
}
} ,
stopBrowsing : function ( ) {
this . selection . category = {
title : '' ,
browsing : false ,
_id : undefined ,
isCategory : false
} ;
this . selection . posts = [ ] ;
this . cardButtons = [ ] ;
} ,
showCreatePostDialog : function ( ) {
if ( ! this . selection . category . isCategory ) {
this . resetSnackbarButton ( ) ;
this . notification ( 'You are not in a category' ) ;
return ;
}
this . dialog . show . createPost = true ;
} ,
createPost : async function ( ) {
if ( ! this . selection . category . isCategory ) {
this . resetSnackbarButton ( ) ;
this . notification ( 'You are not in a category' ) ;
return ;
}
const category = this . selection . category ;
const input = this . dialog . text . createPost ;
const res = await fetch ( ` ${ window . location . origin } /api/v1/content/post/create ` , {
method : 'POST' ,
headers : {
'Accept' : 'application/json' ,
'Content-Type' : 'application/json'
} ,
credentials : 'include' ,
body : JSON . stringify ( {
category : category . _id ,
title : input . title ,
body : input . body
} )
} ) ;
if ( res . status !== 200 ) {
if ( res . status === 401 || res . status === 403 ) {
this . resetSnackbarButton ( ) ;
this . notification ( 'You are not allowed to do that' ) ;
return ;
}
if ( res . status === 429 ) {
this . resetSnackbarButton ( ) ;
this . notification ( 'Chill! You are posting too much!' ) ;
return ;
}
const json = await res . json ( ) ;
this . resetSnackbarButton ( ) ;
this . notification ( getCreatePostError ( json ) ) ;
return ;
} else {
this . resetSnackbarButton ( ) ;
this . notification ( 'Successfully created post' ) ;
this . dialog . show . createPost = false ;
this . browse ( this . selection . category ) ;
return ;
}
} ,
createCategory : async function ( ) {
const input = this . dialog . text . createCategory ;
const res = await fetch ( ` ${ window . location . origin } /api/v1/content/category/create ` , {
method : 'POST' ,
headers : {
'Accept' : 'application/json' ,
'Content-Type' : 'application/json'
} ,
credentials : 'include' ,
body : JSON . stringify ( {
title : input . title
} )
} ) ;
if ( res . status !== 200 ) {
if ( res . status === 401 || res . status === 403 ) {
this . resetSnackbarButton ( ) ;
this . notification ( 'You are not allowed to do that' ) ;
return ;
}
if ( res . status === 429 ) {
this . resetSnackbarButton ( ) ;
this . notification ( 'Chill! You are posting too much!' ) ;
return ;
}
const json = await res . json ( ) ;
this . resetSnackbarButton ( ) ;
this . notification ( getCreateCategoryError ( json ) ) ;
return ;
} else {
this . resetSnackbarButton ( ) ;
this . notification ( 'Successfully created category' ) ;
this . dialog . show . createCategory = false ;
this . browseCategories ( ) ;
return ;
}
} ,
browse : async function ( category ) {
const { _id , title } = category ;
const res = await fetch ( ` ${ window . location . origin } /api/v1/content/category/ ${ _id } /info ` , {
method : 'GET' ,
headers : {
'Accept' : 'application/json' ,
} ,
credentials : 'include'
} ) ;
if ( res . status === 200 ) {
const json = await res . json ( ) ;
this . selection . category . title = title ;
this . selection . category . _id = _id ;
this . selection . category . browsing = true ;
this . selection . category . isCategory = true ;
this . selection . posts = [ ] ;
this . cardButtons = [ ] ;
for ( let i = 0 ; i < json . category . posts . length ; i ++ ) {
const v = json . category . posts [ i ] ;
this . selection . posts . push ( { title : v . title , body : v . body , _id : v . _id , creator : v . creator } ) ;
}
} else {
this . resetSnackbarButton ( ) ;
this . notification ( 'Failed to fetch category' ) ;
}
2020-11-16 21:16:25 +02:00
} ,
openChatForCategory : async function ( categoryId ) {
2020-10-05 20:36:03 +03:00
} ,
browseCategories : async function ( ) {
const res = await fetch ( ` ${ window . location . origin } /api/v1/content/category/list?count=50 ` , {
method : 'GET' ,
headers : {
'Accept' : 'application/json' ,
} ,
credentials : 'include'
} ) ;
if ( res . status === 200 ) {
const json = await res . json ( ) ;
this . selection . category . title = 'categories' ;
this . selection . category . browsing = true ;
this . selection . category . isCategory = false ;
this . selection . posts = [ ] ;
this . cardButtons = [ ] ;
2020-11-16 21:16:25 +02:00
this . button ( 'Chat' , ( post ) => {
this . browse ( post ) ;
} ) ;
2020-10-05 20:36:03 +03:00
this . button ( 'View' , ( post ) => {
this . browse ( post ) ;
} ) ;
for ( let i = 0 ; i < json . categories . length ; i ++ ) {
const v = json . categories [ i ] ;
this . selection . posts . push ( { title : v . title , body : '' , _id : v . _id , creator : v . creator } ) ;
}
} else {
this . resetSnackbarButton ( ) ;
this . notification ( 'Failed to fetch category list' ) ;
}
}
}
} ) ;