From 5c638990cb381c67438868afad4a7438baaa7587 Mon Sep 17 00:00:00 2001 From: lcduong Date: Tue, 23 Jul 2024 13:46:59 +0700 Subject: [PATCH 1/3] use the same ico with eventyay-talk --- webapp/public/favicon.ico | Bin 15406 -> 15406 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/webapp/public/favicon.ico b/webapp/public/favicon.ico index f87d31458f950dcf5ce2cef33b7459f62f88ef16..c9d25512759f55676cd382e9224cf5adc809e9ec 100644 GIT binary patch literal 15406 zcmeHO+iz4w7#|~l06zF$z+j^$6do|BiTFU`3r{?F2{G_yKoi0X@PI)@}T5bjN{SHGZ6l4o+Ieh zA6?N$tKWhC+O=>axGHT-xAbGN2>jBt5yx1Q6aDz`O^9^`p#S*Voao1fC}@?7LD~62 zPV~2XYG6b^4TEj_bE3DK3p@K6mxG`lUg-$hR-1YLLiIq~PdUQuJe!f;k9C+aC}h#e z<4hT1IfBP0yUP#VB+n-|w#&KoXl_jkMoSIGv^p?akAd0O?rH4e`z|w$6i>b%GpeP2 z7s3yC%vO)C&y2uo&`xZeLG6d22H(s4ERI31oXlD_{rtYP{mpLQa?`J$t(5$;%xNEI z|KBcbgIISk4Fh%SZ0D=c_P;+6g81Y=aIe2DgE*-`E(|D^t}gK;nkul1j}`v>Z~K!C^gN83M~7)@a) z^o?iskJhY)frbrfVBf9ujK7xcUcVLex-A93X3#J{;B^PL zc?q`{4K;#!?dO6(Z~7E-v@5RpM;J}kI4&IlqX00w&bjBEc?{&E9s8hQ@-uvQQG@B{ z;%@32`8=cISps8)Suaw4clBs-zNGzU_V#T2N8R-zXnU8~Liu8$Z9TLY?Ehy=C5(^U zvPHD&t)iAc)*awS5RkyLhX;Sh((zXeqSfz~g#6>f{nock{Cg%5>Yhah2jRJDzuCd#;1u@=uQ4ff2PqKs^kcS`XpR?a!m8ZC?!X zTWfgg95H#G7>B|311LW~TXWve{IzLkv*Gv(Y1E4j249rmS(!uPy0D8kV;Q#Nz^gho(yMF?m%a1(sslD<4 zKhaNbw``#`eu8(8Q2!CuQL7)RqvoOuGs4N5WnTzuo8Ew_T_`)v%l5hGDrsi+9cc?` T3+V&)K7gMG$xB)wXAArbaV>9v literal 15406 zcmeHO3s4hB7(T1*C~ZY+ow4Ik8C#f$j`Aplf?5HgKERHM7IoBE5zwktd}HmzvE`w> z0)&uYQ9vM#L6ZVft2Na+$aH88d6PE;6N@6)$JEZ$UiZYS;ke`yNMbs@o%v>O_x9ia z-*5N+yZ!GDg2q5&p-GbFW3?`a`#LyG^D;}3ElY}tM9jSy$8filXVSgNtWl3 zWA(+I6VX29Ws6d7ef|bK1X)kZqO3QEo&#;gC+8Mg%8NjIM?fSmE(rcfS`d5%0XS~M z_Dv+OVlQ7TWk#)%6o&4T6@}%ENWLhzhy|OMR{B*whtox;*+x~4d>DlE&ICDQT?K(eiI#rxnnKs9X;0a_WK!l=|Q%j<)xPON%%fk z=mmQ>>CUBXv?Yt4gQZ;D`v&m$H;4FotnWw4I6fbh5oP-iyC0zE&>XpEn3|8wz~ctd zkM#%6FO&NJ%lylk(cg8RPRzuEygc?x;`K7R`R}ZV&&FH3NS%_sbUm`ZZQI}+{pz}n zDUza4vn9lNfdjU6BhL&@(qEmln^+g#Gm7){KlVk4KY9ZD>~W6%`|T|6d#xoD6n9!n zV?^101at2^{*B*$Hr*iD6@{X^B{SKb`qg0mQJ;?H?&KfQZ=XKw8g$P58~D2-RFx}o zEg>(9ZX~wJIr{N@kc<)Ia{nXA59*T^M=0?iDGV{Wdi=!wW9J)N9v%Orek`AkmWT7N zZY!RsWW{l$^vGYpJq&go=7GNF!OBw!46sLh4!wp{XV=Fo*l}48jK)`fHLIt(8VdH3 z^SZ`^^HBYUrUSF&jCWg=Rmn-J>UD{(g!0UqH9*&o=Ig~E8uc{kIn;0|eSU_N9^qP) z&d<MF2TO7+FGh#CwJp? zeLdB;>#K}-bxrcco=dc7PaQ$e`NLB*XE!jrn~yBSv+;g=)$1BC27@3Y2=Dx}uG8`N zBxugA-wU_1p0{R;reQ~5vXf7@NQqt{;*%l z4YUSx8!HN24`)EXn;q#JZQFHWR|t_WFbeiB5$Ddnhwi=X&a;QVv%!-U@^R%PSpTzAYMPa1<4!*Z@<~)-86R%Nc@{R3_}BbAkTVuuvuC|v+qjE=P0i{zK`g=CkxTgl5276Zzp%F1 zQ+AjAimH|V(&ETr-!Rx?qpdci{lk3%%9rK!i}H`Yzp>2G_9MyN#lNw&V8YMWOCs-F z&yTT0?+yAgWyO-ON8)>s@w&@?YtQF!d!rY)PgHuk{o2bp-iD^bTMQRI-Z2D%-5GLb z4EUCS=v^%SI&~NSgX=${A8!vel68;DxYvHtf13D1uIU02k?#K zi0*CfvLA_m!g~F9*ktm;gPa*#fpY3d?k@YS`A@W7&WQH7=TC7#$nW4A$7_mH@j@a< z>EX8>;T>)3O8y6RAb#B*;QM#fPHVaA?H`$4*6hXBllHroUo79)GRgn5=HGVwx$j!O z4~VrN5}gQmfSo%}D1-RYg`O)}Q_%Z}W!~FX?gwH|3TerLe&C-UN$BCQ=OAp*mV%Jq zIxAOQ#QV-zQ@`O8SxKbyVb}LF;eNC4!-1}uo`&9=?4{zoAahU4r!kh?Bgfi0>LI{; zhhA8S{Kn&vsjsavK%5`k-Q99{1=c|D-isnDU2qrdPx-3qwYjRA%$F zrWp{|KK>5_I|e;}Ul{mz<$pFa!$pFc~|D1t; E05jD%5dZ)H From ec412bfa7e1fbb7a9126340f6a8afc9795345f33 Mon Sep 17 00:00:00 2001 From: lcduong Date: Tue, 17 Sep 2024 15:07:26 +0700 Subject: [PATCH 2/3] update base path for webapp using basePath from config file --- .../migrations/0066_alter_world_domain.py | 28 +++++++++++++++++++ server/venueless/core/models/world.py | 2 +- server/venueless/settings.py | 7 ++--- webapp/config.js | 5 ++-- webapp/src/main.js | 12 ++++++-- webapp/src/router/index.js | 4 ++- webapp/src/theme.js | 2 +- webapp/vue.config.js | 6 ++-- 8 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 server/venueless/core/migrations/0066_alter_world_domain.py diff --git a/server/venueless/core/migrations/0066_alter_world_domain.py b/server/venueless/core/migrations/0066_alter_world_domain.py new file mode 100644 index 00000000..541011dc --- /dev/null +++ b/server/venueless/core/migrations/0066_alter_world_domain.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.14 on 2024-09-17 03:37 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0065_chat_mentions"), + ] + + operations = [ + migrations.AlterField( + model_name="world", + name="domain", + field=models.CharField( + blank=True, + max_length=250, + null=True, + unique=True, + validators=[ + django.core.validators.RegexValidator( + regex="^[a-z0-9-.:]+(/[a-zA-Z0-9-_./]*)?$" + ) + ], + ), + ), + ] diff --git a/server/venueless/core/models/world.py b/server/venueless/core/models/world.py index adcf256f..cb7695b4 100644 --- a/server/venueless/core/models/world.py +++ b/server/venueless/core/models/world.py @@ -138,7 +138,7 @@ class World(VersionedModel): unique=True, null=True, blank=True, - validators=[RegexValidator(regex=r"^[a-z0-9-.:]+$")], + validators=[RegexValidator(regex=r"^[a-z0-9-.:]+(/[a-zA-Z0-9-_./]*)?$")], ) locale = models.CharField( max_length=100, diff --git a/server/venueless/settings.py b/server/venueless/settings.py index 304718ce..46bbfd9b 100644 --- a/server/venueless/settings.py +++ b/server/venueless/settings.py @@ -309,10 +309,9 @@ ROOT_URLCONF = "venueless.urls" CORS_ORIGIN_REGEX_WHITELIST = [ - r"^https?://(\w+\.)?eventyay\.com$", # Allow any subdomain of eventyay.com - r"^https?://video\.eventyay\.com(:\d+)?$", # Allow video.eventyay.com with any port - r"^https?://video-dev\.eventyay\.com(:\d+)?$", # Allow video-dev.eventyay.com with any port - r"^https?://wikimania-live\.eventyay\.com(:\d+)?$", # Allow wikimania-live.eventyay.com with any port + r"^https?://([\w\-]+\.)?eventyay\.com$", # Allow any subdomain of eventyay.com + r"^https?://app-test\.eventyay\.com(:\d+)?$", # Allow video-dev.eventyay.com with any port + r"^https?://app\.eventyay\.com(:\d+)?$", # Allow wikimania-live.eventyay.com with any port ] if DEBUG: CORS_ORIGIN_REGEX_WHITELIST = [ diff --git a/webapp/config.js b/webapp/config.js index 616ed23e..74cc3ed2 100644 --- a/webapp/config.js +++ b/webapp/config.js @@ -17,7 +17,7 @@ if (ENV_DEVELOPMENT || !window.venueless) { locales: ['en', 'de', 'pt_BR', 'ar', 'fr', 'es', 'uk', 'ru'], theme: { logo: { - url: '/eventyay-video-logo.svg', + url: '/video/eventyay-video-logo.svg', fitToWidth: false }, colors: { @@ -25,7 +25,8 @@ if (ENV_DEVELOPMENT || !window.venueless) { sidebar: '#2185d0', bbb_background: '#ffffff', } - } + }, + basePath: '/video', } } else { // load from index.html as `window.venueless = {…}` diff --git a/webapp/src/main.js b/webapp/src/main.js index 2b16d074..4a8d86dd 100644 --- a/webapp/src/main.js +++ b/webapp/src/main.js @@ -50,19 +50,25 @@ async function init({token, inviteToken}) { window.vapp = app store.commit('setUserLocale', i18n.resolvedLanguage) store.dispatch('updateUserTimezone', localStorage.userTimezone || moment.tz.guess()) + // Get the path relative to the publicPath + const basePath = config.basePath || '' + let relativePath = location.pathname.replace(basePath, '') + if (!relativePath) { + relativePath = '/' + } - const { route } = router.resolve(location.pathname) + const { route } = router.resolve(relativePath) const anonymousRoomId = route.name === 'standalone:anonymous' ? route.params.roomId : null if (token) { localStorage.token = token - router.replace(location.pathname) + router.replace(relativePath) store.dispatch('login', {token}) } else if (localStorage.token) { store.dispatch('login', {token: localStorage.token}) } else if (inviteToken && anonymousRoomId) { const clientId = uuid() localStorage[`clientId:room:${anonymousRoomId}`] = clientId - router.replace(location.pathname) + router.replace(relativePath) store.dispatch('login', {clientId, inviteToken}) } else if (anonymousRoomId && localStorage[`clientId:room:${anonymousRoomId}`]) { const clientId = localStorage[`clientId:room:${anonymousRoomId}`] diff --git a/webapp/src/router/index.js b/webapp/src/router/index.js index 9d1b7a1f..3ba2992b 100644 --- a/webapp/src/router/index.js +++ b/webapp/src/router/index.js @@ -13,6 +13,8 @@ import Speaker from 'views/schedule/speakers/item' import Exhibitor from 'views/exhibitors/item' import ContactRequests from 'views/contact-requests' import Preferences from 'views/preferences' +import config from 'config' + Vue.use(VueRouter) @@ -240,7 +242,7 @@ const routes = [{ const router = new VueRouter({ mode: 'history', - base: process.env.BASE_URL, + base: config.basePath, routes }) diff --git a/webapp/src/theme.js b/webapp/src/theme.js index d07038d8..53d8cabb 100644 --- a/webapp/src/theme.js +++ b/webapp/src/theme.js @@ -53,7 +53,7 @@ const DEFAULT_COLORS = { } const DEFAULT_LOGO = { - url: '/eventyay-video-logo.svg', + url: '/video/eventyay-video-logo.svg', fitToWidth: false } diff --git a/webapp/vue.config.js b/webapp/vue.config.js index 0c388c8c..4e0338c2 100644 --- a/webapp/vue.config.js +++ b/webapp/vue.config.js @@ -11,12 +11,12 @@ module.exports = { devServer: { host: '0.0.0.0', port: 8880, - public: 'video-dev.eventyay.com', + public: 'app-test.eventyay.com', allowedHosts: [ '.localhost', '.eventyay.com', - 'video-dev.eventyay.com', - 'video.eventyay.com' + 'app-test.eventyay.com', + 'app.eventyay.com' ], }, pwa: { From 3ca293d9f6dd95fc861cee0478ce4dd2cf6f38c6 Mon Sep 17 00:00:00 2001 From: lcduong Date: Mon, 23 Sep 2024 14:46:21 +0700 Subject: [PATCH 3/3] Handle multiple language --- webapp/src/views/schedule/index.vue | 106 ++++++++++++++++++- webapp/src/views/schedule/sessions/index.vue | 106 ++++++++++++++++++- 2 files changed, 202 insertions(+), 10 deletions(-) diff --git a/webapp/src/views/schedule/index.vue b/webapp/src/views/schedule/index.vue index b0cca37f..be0a1e04 100644 --- a/webapp/src/views/schedule/index.vue +++ b/webapp/src/views/schedule/index.vue @@ -154,9 +154,26 @@ export default { let founds = null if (selectedIds.length) { if (results && results.length) { - founds = self.schedule.talks.filter(t => selectedIds.includes(t[refKey]) && results && results.includes(t.id))?.map(i => i.id) || [] + founds = self.schedule.talks.filter(t => { + if (refKey === 'session_type') { + if (typeof t.session_type === 'string') { + return selectedIds.includes(t.session_type) && results.includes(t.id) + } else { + return Object.keys(t.session_type).some(key => selectedIds.includes(t.session_type[key])) && results.includes(t.id) + } + } + return selectedIds.includes(t[refKey]) && results && results.includes(t.id)})?.map(i => i.id) || [] } else { - founds = self.schedule.talks.filter(t => { return selectedIds.includes(t[refKey]) })?.map(i => i.id) || [] + founds = self.schedule.talks.filter(t => { + if (refKey === 'session_type') { + if (typeof t.session_type === 'string') { + return selectedIds.includes(t.session_type) + } else { + return Object.keys(t.session_type).some(key => selectedIds.includes(t.session_type[key])) + } + } + return selectedIds.includes(t[refKey]) + })?.map(i => i.id) || [] } results = founds } @@ -204,9 +221,45 @@ export default { }, filter() { const filter = this.defaultFilter - filter.tracks.data = this.schedule.tracks.map(t => { t.value = t.id; t.label = t.name; return t }) - filter.rooms.data = this.schedule.rooms.map(t => { t.value = t.id; t.label = t.name; return t }) - filter.types.data = this.schedule.session_type.map(t => { t.value = t.session_type; t.label = t.session_type; return t }) + const setSessionType = new Set() + const enLanguage = 'en' + + this.schedule.session_type.forEach(t => { + if (typeof t.session_type === 'string') { + setSessionType.add(t.session_type) + } else { + const sessionTypeKeyArray = Object.keys(t.session_type) + let isEnglish = false + + for (let i = 0; i < sessionTypeKeyArray.length; i++) { + if (sessionTypeKeyArray[i] === this.getLanguage()) { + setSessionType.add(t.session_type[sessionTypeKeyArray[i]]) + break + } + else if (sessionTypeKeyArray[i] === enLanguage) { + isEnglish = true + if (i === sessionTypeKeyArray.length - 1) { + setSessionType.add(t.session_type[enLanguage]) + } + } + else { + if (i === sessionTypeKeyArray.length - 1) { + if (isEnglish) { + setSessionType.add(t.session_type[enLanguage]) + } + else { + setSessionType.add(t.session_type[sessionTypeKeyArray[i]]) + } + } + } + } + } + }) + + filter.types.data = Array.from(setSessionType).map(t => { return { value: t, label: t } }) + filter.tracks.data = this.filterLanguage(this.schedule.tracks) + filter.rooms.data = this.filterLanguage(this.schedule.rooms) + return filter } }, @@ -296,6 +349,49 @@ export default { }, resetOnlyFavs() { this.onlyFavs = false + }, + getLanguage() { + return localStorage.getItem('userLanguage') || 'en' + }, + filterLanguage(data) { + const setMap = new Map() + const enLanguage = 'en' + + data.forEach( + t => { + if (typeof t.name === 'string') { + setMap.set(t.id, t.name) + } else { + const keyArray = Object.keys(t.name) + let isEnglish = false + + for (let i = 0; i < keyArray.length; i++) { + if (keyArray[i] === this.getLanguage()) { + setMap.set(t.id, t.name[keyArray[i]]) + break + } + else if (keyArray[i] === enLanguage) { + isEnglish = true + if (i === keyArray.length - 1) { + setMap.set(t.id, t.name[enLanguage]) + } + } + else { + if (i === keyArray.length - 1) { + if (isEnglish) { + setMap.set(t.id, t.name[enLanguage]) + } + else { + setMap.set(t.id, t.name[keyArray[i]]) + } + } + } + } + } + } + ) + + return Array.from(setMap).map(t => { return { value: t[0], label: t[1] } }) } } } diff --git a/webapp/src/views/schedule/sessions/index.vue b/webapp/src/views/schedule/sessions/index.vue index f82b86c5..95f6203e 100644 --- a/webapp/src/views/schedule/sessions/index.vue +++ b/webapp/src/views/schedule/sessions/index.vue @@ -142,9 +142,26 @@ export default { let founds = null if (selectedIds.length) { if (results && results.length) { - founds = self.schedule.talks.filter(t => selectedIds.includes(t[refKey]) && results && results.includes(t.id))?.map(i => i.id) || [] + founds = self.schedule.talks.filter(t => { + if (refKey === 'session_type') { + if (typeof t.session_type === 'string') { + return selectedIds.includes(t.session_type) && results.includes(t.id) + } else { + return Object.keys(t.session_type).some(key => selectedIds.includes(t.session_type[key])) && results.includes(t.id) + } + } + return selectedIds.includes(t[refKey]) && results && results.includes(t.id)})?.map(i => i.id) || [] } else { - founds = self.schedule.talks.filter(t => { return selectedIds.includes(t[refKey]) })?.map(i => i.id) || [] + founds = self.schedule.talks.filter(t => { + if (refKey === 'session_type') { + if (typeof t.session_type === 'string') { + return selectedIds.includes(t.session_type) + } else { + return Object.keys(t.session_type).some(key => selectedIds.includes(t.session_type[key])) + } + } + return selectedIds.includes(t[refKey]) + })?.map(i => i.id) || [] } results = founds } @@ -192,9 +209,45 @@ export default { }, filter() { const filter = this.defaultFilter - filter.tracks.data = this.schedule.tracks.map(t => { t.value = t.id; t.label = t.name; return t }) - filter.rooms.data = this.schedule.rooms.map(t => { t.value = t.id; t.label = t.name; return t }) - filter.types.data = this.schedule.session_type.map(t => { t.value = t.session_type; t.label = t.session_type; return t }) + const setSessionType = new Set() + const enLanguage = 'en' + + this.schedule.session_type.forEach(t => { + if (typeof t.session_type === 'string') { + setSessionType.add(t.session_type) + } else { + const sessionTypeKeyArray = Object.keys(t.session_type) + let isEnglish = false + + for (let i = 0; i < sessionTypeKeyArray.length; i++) { + if(sessionTypeKeyArray[i] === this.getLanguage()) { + setSessionType.add(t.session_type[sessionTypeKeyArray[i]]) + break + } + else if (sessionTypeKeyArray[i] === enLanguage) { + isEnglish = true + if(i === sessionTypeKeyArray.length - 1) { + setSessionType.add(t.session_type[enLanguage]) + } + } + else { + if (i === sessionTypeKeyArray.length - 1) { + if(isEnglish){ + setSessionType.add(t.session_type[enLanguage]) + } + else { + setSessionType.add(t.session_type[sessionTypeKeyArray[i]]) + } + + } + } + } + } + }) + + filter.types.data = Array.from(setSessionType).map(t => { return { value: t, label: t } }) + filter.rooms.data = this.filterLanguage(this.schedule.rooms) + filter.tracks.data = this.filterLanguage(this.schedule.tracks) return filter } }, @@ -284,6 +337,49 @@ export default { }, resetOnlyFavs() { this.onlyFavs = false + }, + getLanguage() { + return localStorage.getItem('userLanguage') || 'en' + }, + filterLanguage(data) { + const setMap = new Map() + const enLanguage = 'en' + + data.forEach( + t => { + if (typeof t.name === 'string') { + setMap.set(t.id, t.name) + } else { + const keyArray = Object.keys(t.name) + let isEnglish = false + + for (let i = 0; i < keyArray.length; i++) { + if (keyArray[i] === this.getLanguage()) { + setMap.set(t.id, t.name[keyArray[i]]) + break + } + else if (keyArray[i] === enLanguage) { + isEnglish = true + if (i === keyArray.length - 1) { + setMap.set(t.id, t.name[enLanguage]) + } + } + else { + if (i === keyArray.length - 1) { + if (isEnglish) { + setMap.set(t.id, t.name[enLanguage]) + } + else { + setMap.set(t.id, t.name[keyArray[i]]) + } + } + } + } + } + } + ) + + return Array.from(setMap).map(t => { return { value: t[0], label: t[1] } }) } } }