diff --git a/.gitea/workflows/cd-deploy.yaml b/.gitea/workflows/cd-deploy.yaml index 4690628..98e5593 100644 --- a/.gitea/workflows/cd-deploy.yaml +++ b/.gitea/workflows/cd-deploy.yaml @@ -1,8 +1,8 @@ name: Continuous Deployment on: push: - branches: - - main + tags: + - '*' jobs: Deploy: @@ -17,15 +17,22 @@ jobs: groupadd -g 989 nginx || true useradd nginx -u 990 -g nginx -m || true - - name: Verify Node Environment + - name: Update Node Environment + uses: actions/setup-node@v6 + with: + node-version: 20.19 + + - name: Verify Local Environment run: | which npm npm -v which node node -v + which sed + sed --version - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 ref: 'main' @@ -36,38 +43,53 @@ jobs: cp /workspace/17th-Ranger-Battalion-ORG/milsim-site-v4/.git/config .git/config chown nginx:nginx .git/config - - name: Fix File Permissions - run: | - sudo chown -R nginx:nginx /var/www/html/milsim-site-v4 - sudo chmod -R u+w /var/www/html/milsim-site-v4 - - name: Update Application Code run: | cd /var/www/html/milsim-site-v4 + version=`git log -1 --format=%H` + echo "Current Revision: $version" + echo "Updating to: ${{ github.sha }} sudo -u nginx git reset --hard sudo -u nginx git pull origin main + sudo -u nginx git pull origin main + new_version=`git log -1 --format=%H` + echo "Sucessfully updated to: $new_version - - name: Update Shared Dependencies + - name: Update Shared Dependencies and Fix Permissions run: | cd /var/www/html/milsim-site-v4/shared - sudo -u nginx -E npm install + npm install + chown -R nginx:nginx . - - name: Update UI Dependencies + - name: Update UI Dependencies and Fix Permissions run: | cd /var/www/html/milsim-site-v4/ui - sudo -u nginx -E npm install + npm install + chown -R nginx:nginx . - - name: Update API Dependencies + - name: Update API Dependencies and Fix Permissions run: | cd /var/www/html/milsim-site-v4/api - sudo -u nginx -E npm install + npm install + chown -R nginx:nginx . - - name: Build UI + - name: Build UI / Update Version / Fix Permissions run: | cd /var/www/html/milsim-site-v4/ui - sudo -u nginx -E npm run build + npm run build + version=`git describe --abbrev=0 --tags` + sed -i "s/VITE_APPLICATION_VERSION=.*/VITE_APPLICATION_VERSION=$version/" .env + chown -R nginx:nginx . - - name: Build API + - name: Build API / Update Version / Fix Permissions run: | cd /var/www/html/milsim-site-v4/api - sudo -u nginx -E npm run build + npm run build + version=`git describe --abbrev=0 --tags` + sed -i "s/APPLICATION_VERSION=.*/APPLICATION_VERSION=$version/" .env + chown -R nginx:nginx . + + - name: Reset File Permissions + run: | + sudo chown -R nginx:nginx /var/www/html/milsim-site-v4 + sudo chmod -R u+w /var/www/html/milsim-site-v4 \ No newline at end of file diff --git a/.gitea/workflows/ci-deploy.yaml b/.gitea/workflows/ci-deploy.yaml new file mode 100644 index 0000000..95ebb3d --- /dev/null +++ b/.gitea/workflows/ci-deploy.yaml @@ -0,0 +1,89 @@ +name: Continuous Integration +on: + push: + branches: + - main + +jobs: + Deploy: + name: Update Development + runs-on: ubuntu-latest + container: + volumes: + - /var/www/html/milsim-site-v4-dev:/var/www/html/milsim-site-v4:z + steps: + - name: Setup Local Environment + run: | + groupadd -g 989 nginx || true + useradd nginx -u 990 -g nginx -m || true + + - name: Update Node Environment + uses: actions/setup-node@v6 + with: + node-version: 20.19 + + - name: Verify Local Environment + run: | + which npm + npm -v + which node + node -v + which sed + sed --version + + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + ref: 'main' + + - name: Token Copy + run: | + cd /var/www/html/milsim-site-v4 + cp /workspace/17th-Ranger-Battalion-ORG/milsim-site-v4/.git/config .git/config + chown nginx:nginx .git/config + + - name: Update Application Code + run: | + cd /var/www/html/milsim-site-v4 + sudo -u nginx git reset --hard + sudo -u nginx git pull origin main + + - name: Update Shared Dependencies and Fix Permissions + run: | + cd /var/www/html/milsim-site-v4/shared + npm install + chown -R nginx:nginx . + + - name: Update UI Dependencies and Fix Permissions + run: | + cd /var/www/html/milsim-site-v4/ui + npm install + chown -R nginx:nginx . + + - name: Update API Dependencies and Fix Permissions + run: | + cd /var/www/html/milsim-site-v4/api + npm install + chown -R nginx:nginx . + + - name: Build UI / Update Version / Fix Permissions + run: | + cd /var/www/html/milsim-site-v4/ui + npm run build + version=`git rev-parse --short=10 HEAD` + sed -i "s/VITE_APPLICATION_VERSION=.*/VITE_APPLICATION_VERSION=$version/" .env + chown -R nginx:nginx . + + - name: Build API / Update Version / Fix Permissions + run: | + cd /var/www/html/milsim-site-v4/api + npm run build + version=`git rev-parse --short=10 HEAD` + sed -i "s/APPLICATION_VERSION=.*/APPLICATION_VERSION=$version/" .env + chown -R nginx:nginx . + + - name: Reset File Permissions + run: | + sudo chown -R nginx:nginx /var/www/html/milsim-site-v4 + sudo chmod -R u+w /var/www/html/milsim-site-v4 \ No newline at end of file diff --git a/api/.env.example b/api/.env.example index 21bf82e..8bfe497 100644 --- a/api/.env.example +++ b/api/.env.example @@ -19,6 +19,8 @@ AUTH_END_SESSION_URI= SERVER_PORT=3000 CLIENT_URL= # This is whatever URL the client web app is served on CLIENT_DOMAIN= #whatever.com +APPLICATION_VERSION= # Should match release tag +APPLICATION_ENVIRONMENT= # dev / prod # Glitchtip GLITCHTIP_DSN= diff --git a/api/src/index.js b/api/src/index.js index 383b0c9..00bf5cc 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -20,11 +20,14 @@ const port = process.env.SERVER_PORT; //glitchtip setup const sentry = require('@sentry/node'); -if (process.env.DISABLE_GLITCHTIP) { +if (process.env.DISABLE_GLITCHTIP === "true") { console.log("Glitchtip disabled") } else { let dsn = process.env.GLITCHTIP_DSN; - sentry.init({ dsn: dsn }); + let release = process.env.APPLICATION_VERSION; + let environment = process.env.APPLICATION_ENVIRONMENT; + console.log(release, environment) + sentry.init({ dsn: dsn, release: release, environment: environment }); console.log("Glitchtip initialized"); } @@ -58,6 +61,7 @@ const { roles, memberRoles } = require('./routes/roles'); const { courseRouter, eventRouter } = require('./routes/course'); const { calendarRouter } = require('./routes/calendar') const morgan = require('morgan'); +const { env } = require('process'); app.use('/application', applicationsRouter); app.use('/ranks', ranks); diff --git a/api/src/routes/auth.js b/api/src/routes/auth.js index c0a089b..c736f33 100644 --- a/api/src/routes/auth.js +++ b/api/src/routes/auth.js @@ -21,12 +21,13 @@ passport.use(new OpenIDConnectStrategy({ scope: ['openid', 'profile'] }, async function verify(issuer, sub, profile, jwtClaims, accessToken, refreshToken, params, cb) { - // console.log('--- OIDC verify() called ---'); - // console.log('issuer:', issuer); - // console.log('sub:', sub); + console.log('--- OIDC verify() called ---'); + console.log('issuer:', issuer); + console.log('sub:', sub); // console.log('profile:', JSON.stringify(profile, null, 2)); - // console.log('id_token claims:', JSON.stringify(jwtClaims, null, 2)); - // console.log('preferred_username:', jwtClaims?.preferred_username); + console.log('profile:', profile); + console.log('id_token claims:', JSON.stringify(jwtClaims, null, 2)); + console.log('preferred_username:', jwtClaims?.preferred_username); const con = await pool.getConnection(); try { diff --git a/api/src/services/calendarService.ts b/api/src/services/calendarService.ts index c88f671..7aa2cee 100644 --- a/api/src/services/calendarService.ts +++ b/api/src/services/calendarService.ts @@ -123,15 +123,9 @@ export async function setAttendanceStatus(memberID: number, eventID: number, sta } export async function getEventAttendance(eventID: number): Promise { - const sql = ` - SELECT - s.member_id, - s.status, - m.name AS member_name - FROM calendar_events_signups s - LEFT JOIN members m ON s.member_id = m.id - WHERE s.event_id = ? - `; - return await pool.query(sql, [eventID]); + const sql = "CALL `sp_GetCalendarEventSignups`(?)" + const res = await pool.query(sql, [eventID]); + console.log(res[0]); + return res[0]; } \ No newline at end of file diff --git a/ecosystem.config.js b/ecosystem.config.js index 68925cc..aa2c2ed 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -5,6 +5,7 @@ module.exports = { script: 'built/api/src/index.js', watch: ['.env', 'built'], ignore_watch: ['.gitignore', '\.json', 'src', '\.db', 'node_modules'], + appendEnvToName: true, watch_options: { usePolling: true, interval: 10000 diff --git a/shared/types/calendar.ts b/shared/types/calendar.ts index 526068f..5a62a8b 100644 --- a/shared/types/calendar.ts +++ b/shared/types/calendar.ts @@ -26,6 +26,7 @@ export interface CalendarSignup { eventID: number; status: CalendarAttendance; member_name?: string; + member_unit?: string; } export interface CalendarEventShort { diff --git a/ui/.env.example b/ui/.env.example index 57810b0..9a0998f 100644 --- a/ui/.env.example +++ b/ui/.env.example @@ -2,6 +2,8 @@ VITE_APIHOST= VITE_DOCHOST= # https://bookstack.whatever.com/api VITE_ENVIRONMENT= # dev / prod +VITE_APPLICATION_VERSION= # Should match release tag + # Glitchtip VITE_GLITCHTIP_DSN= diff --git a/ui/src/components/Navigation/Navbar.vue b/ui/src/components/Navigation/Navbar.vue index 72c5bd4..c56d592 100644 --- a/ui/src/components/Navigation/Navbar.vue +++ b/ui/src/components/Navigation/Navbar.vue @@ -156,6 +156,12 @@ function blurAfter() { Join + + + + Calendar + + diff --git a/ui/src/components/calendar/ViewCalendarEvent.vue b/ui/src/components/calendar/ViewCalendarEvent.vue index 39be30d..c99e0dc 100644 --- a/ui/src/components/calendar/ViewCalendarEvent.vue +++ b/ui/src/components/calendar/ViewCalendarEvent.vue @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/ui/src/main.js b/ui/src/main.js index 4d1080a..c7de1da 100644 --- a/ui/src/main.js +++ b/ui/src/main.js @@ -20,10 +20,12 @@ const app = createApp(App) app.use(createPinia()) app.use(router) -if (!import.meta.env.VITE_DISABLE_GLITCHTIP) { +if (import.meta.env.VITE_DISABLE_GLITCHTIP === "true") { + console.log("Glitchtip disabled"); +} else { let dsn = import.meta.env.VITE_GLITCHTIP_DSN; let environment = import.meta.env.VITE_ENVIRONMENT; - + let release = import.meta.env.VITE_APPLICATION_VERSION; Sentry.init({ app, dsn: dsn, @@ -32,7 +34,7 @@ if (!import.meta.env.VITE_DISABLE_GLITCHTIP) { ], tracesSampleRate: 0.01, environment: environment, - release: 'release tag' + release: release }); } diff --git a/ui/src/pages/Calendar.vue b/ui/src/pages/Calendar.vue index 2f4c76e..df9868b 100644 --- a/ui/src/pages/Calendar.vue +++ b/ui/src/pages/Calendar.vue @@ -3,15 +3,14 @@ import { ref, watch, nextTick, computed, onMounted } from 'vue' import FullCalendar from '@fullcalendar/vue3' import dayGridPlugin from '@fullcalendar/daygrid' import interactionPlugin from '@fullcalendar/interaction' -import { X, Clock, MapPin, User, ListTodo, ChevronLeft, ChevronRight, Plus } from 'lucide-vue-next' +import { ChevronLeft, ChevronRight, Plus } from 'lucide-vue-next' import CreateCalendarEvent from '@/components/calendar/CreateCalendarEvent.vue' -import { getCalendarEvent, getMonthCalendarEvents } from '@/api/calendar' -import { CalendarEvent, CalendarEventShort } from '@shared/types/calendar' -import { Calendar } from '@fullcalendar/core' +import { CalendarEvent } from '@shared/types/calendar' import ViewCalendarEvent from '@/components/calendar/ViewCalendarEvent.vue' import { useRouter, useRoute } from 'vue-router' import { useCalendarEvents } from '@/composables/useCalendarEvents' import { useCalendarNavigation } from '@/composables/useCalendarNavigation' +import { useUserStore } from '@/stores/user' const monthLabels = [ 'January', 'February', 'March', 'April', 'May', 'June', @@ -24,13 +23,14 @@ function api() { const router = useRouter(); const route = useRoute(); +const userStore = useUserStore(); function buildFullDate(month: number, year: number): Date { return new Date(year, month, 1); //default to first of month } const { selectedMonth, selectedYear, years, goPrev, goNext, goToday, onDatesSet, goToSelectedDate } = useCalendarNavigation(api) -const { events, loadEvents} = useCalendarEvents(selectedMonth, selectedYear); +const { events, loadEvents } = useCalendarEvents(selectedMonth, selectedYear); const panelOpen = ref(false) const activeEvent = ref(null) @@ -48,6 +48,7 @@ const dialogRef = ref(null) // NEW: handle day/time slot clicks to start creating an event function onDateClick(arg: { dateStr: string }) { + if (!userStore.isLoggedIn) return; dialogRef.value?.openDialog(arg.dateStr); // For now, just open the panel with a draft payload. // activeEvent.value = { @@ -202,7 +203,7 @@ onMounted(() => { @click="goToday"> Today -