fixed scripts and replaced consts
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
# Production environment variables for KSPGUTI Schedule
|
# Production environment variables for KSPGUTI Schedule
|
||||||
|
|
||||||
|
# Site URL - used for canonical links and sitemap (optional, defaults to https://schedule.itlxrd.space)
|
||||||
|
NEXT_PUBLIC_SITE_URL=https://schedule.itlxrd.space
|
||||||
|
|
||||||
# Proxy URL for schedule parsing (optional, defaults to https://lk.ks.psuti.ru)
|
# Proxy URL for schedule parsing (optional, defaults to https://lk.ks.psuti.ru)
|
||||||
PROXY_URL=https://lk.ks.psuti.ru
|
PROXY_URL=https://lk.ks.psuti.ru
|
||||||
|
|
||||||
|
|||||||
17
.example.env
17
.example.env
@@ -1,2 +1,15 @@
|
|||||||
PROXY_HOST=
|
# Development/Example environment variables for KSPGUTI Schedule
|
||||||
PARSING_FAILURE_NOTIFICATIONS_TELEGRAM_BOTAPI_TOKEN=
|
|
||||||
|
# Site URL - used for canonical links and sitemap (optional, defaults to https://schedule.itlxrd.space)
|
||||||
|
NEXT_PUBLIC_SITE_URL=https://schedule.itlxrd.space
|
||||||
|
|
||||||
|
# Proxy URL for schedule parsing (optional, defaults to https://lk.ks.psuti.ru)
|
||||||
|
PROXY_URL=https://lk.ks.psuti.ru
|
||||||
|
|
||||||
|
# Telegram Bot API token for parsing failure notifications (optional)
|
||||||
|
# Get token from @BotFather on Telegram
|
||||||
|
PARSING_FAILURE_NOTIFICATIONS_TELEGRAM_BOTAPI_TOKEN=
|
||||||
|
|
||||||
|
# Telegram Chat ID for receiving notifications (optional)
|
||||||
|
# You can get your chat ID by messaging @userinfobot on Telegram
|
||||||
|
PARSING_FAILURE_NOTIFICATIONS_TELEGRAM_CHAT_ID=
|
||||||
@@ -3,4 +3,4 @@ Disallow: /
|
|||||||
Allow: /ps7
|
Allow: /ps7
|
||||||
Allow: /pks35k
|
Allow: /pks35k
|
||||||
|
|
||||||
Sitemap: https://kspsuti.ru/sitemap.xml
|
Sitemap: https://schedule.itlxrd.space/sitemap.xml
|
||||||
@@ -155,13 +155,34 @@ npm ci --legacy-peer-deps --production=false
|
|||||||
echo -e "${YELLOW}Building the application...${NC}"
|
echo -e "${YELLOW}Building the application...${NC}"
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
|
# Check if service user exists, create if not
|
||||||
|
echo -e "${YELLOW}Checking service user...${NC}"
|
||||||
|
if ! id "$SERVICE_USER" &>/dev/null; then
|
||||||
|
echo -e "${YELLOW}User $SERVICE_USER does not exist. Creating...${NC}"
|
||||||
|
# Try to create user, fallback to current user if fails
|
||||||
|
if useradd -r -s /bin/false -d "$INSTALL_DIR" "$SERVICE_USER" 2>/dev/null; then
|
||||||
|
echo -e "${GREEN}User $SERVICE_USER created${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Could not create user $SERVICE_USER. Using current user instead.${NC}"
|
||||||
|
SERVICE_USER=$(whoami)
|
||||||
|
SERVICE_GROUP=$(id -gn)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}User $SERVICE_USER exists${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
# Set ownership
|
# Set ownership
|
||||||
echo -e "${YELLOW}Setting ownership...${NC}"
|
echo -e "${YELLOW}Setting ownership...${NC}"
|
||||||
chown -R "$SERVICE_USER:$SERVICE_GROUP" "$INSTALL_DIR"
|
chown -R "$SERVICE_USER:$SERVICE_GROUP" "$INSTALL_DIR"
|
||||||
|
|
||||||
# Install systemd service
|
# Install systemd service
|
||||||
echo -e "${YELLOW}Installing systemd service...${NC}"
|
echo -e "${YELLOW}Installing systemd service...${NC}"
|
||||||
cp "$INSTALL_DIR/systemd/$SERVICE_NAME.service" "/etc/systemd/system/"
|
# Create temporary service file with correct user/group
|
||||||
|
cp "$INSTALL_DIR/systemd/$SERVICE_NAME.service" "/tmp/$SERVICE_NAME.service"
|
||||||
|
# Update user/group in service file
|
||||||
|
sed -i "s/^User=.*/User=$SERVICE_USER/g; s/^Group=.*/Group=$SERVICE_GROUP/g" "/tmp/$SERVICE_NAME.service"
|
||||||
|
cp "/tmp/$SERVICE_NAME.service" "/etc/systemd/system/$SERVICE_NAME.service"
|
||||||
|
rm -f "/tmp/$SERVICE_NAME.service"
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
|
||||||
# Enable service
|
# Enable service
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import contentTypeParser from 'content-type'
|
|||||||
import { JSDOM } from 'jsdom'
|
import { JSDOM } from 'jsdom'
|
||||||
// import { content as mockContent } from './mock'
|
// import { content as mockContent } from './mock'
|
||||||
import { reportParserError } from '@/app/logger'
|
import { reportParserError } from '@/app/logger'
|
||||||
|
import { PROXY_URL } from '@/shared/constants/urls'
|
||||||
|
|
||||||
// ПС-7: 146
|
// ПС-7: 146
|
||||||
export async function getSchedule(groupID: number, groupName: string): Promise<Day[]> {
|
export async function getSchedule(groupID: number, groupName: string): Promise<Day[]> {
|
||||||
const page = await fetch(`${process.env.PROXY_URL ?? 'https://lk.ks.psuti.ru'}/?mn=2&obj=${groupID}`)
|
const page = await fetch(`${PROXY_URL}/?mn=2&obj=${groupID}`)
|
||||||
// const page = { text: async () => mockContent, status: 200, headers: { get: (s: string) => s && 'text/html' } }
|
// const page = { text: async () => mockContent, status: 200, headers: { get: (s: string) => s && 'text/html' } }
|
||||||
const content = await page.text()
|
const content = await page.text()
|
||||||
const contentType = page.headers.get('content-type')
|
const contentType = page.headers.get('content-type')
|
||||||
@@ -16,7 +17,7 @@ export async function getSchedule(groupID: number, groupName: string): Promise<D
|
|||||||
const root = new JSDOM(content).window.document
|
const root = new JSDOM(content).window.document
|
||||||
return parsePage(root, groupName)
|
return parsePage(root, groupName)
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error('Error while parsing lk.ks.psuti.ru')
|
console.error(`Error while parsing ${PROXY_URL}`)
|
||||||
reportParserError(new Date().toISOString(), 'Не удалось сделать парсинг для группы', groupName)
|
reportParserError(new Date().toISOString(), 'Не удалось сделать парсинг для группы', groupName)
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
@@ -24,6 +25,6 @@ export async function getSchedule(groupID: number, groupName: string): Promise<D
|
|||||||
console.error(page.status, contentType)
|
console.error(page.status, contentType)
|
||||||
console.error(content.length > 500 ? content.slice(0, 500 - 3) + '...' : content)
|
console.error(content.length > 500 ? content.slice(0, 500 - 3) + '...' : content)
|
||||||
reportParserError(new Date().toISOString(), 'Не удалось получить страницу для группы', groupName)
|
reportParserError(new Date().toISOString(), 'Не удалось получить страницу для группы', groupName)
|
||||||
throw new Error('Error while fetching lk.ks.psuti.ru')
|
throw new Error(`Error while fetching ${PROXY_URL}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,7 @@ import Link from 'next/link'
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import { BsTelegram } from 'react-icons/bs'
|
import { BsTelegram } from 'react-icons/bs'
|
||||||
import { SlSocialVkontakte } from 'react-icons/sl'
|
import { SlSocialVkontakte } from 'react-icons/sl'
|
||||||
|
import { TELEGRAM_CONTACT_URL } from '@/shared/constants/urls'
|
||||||
|
|
||||||
export function AddGroupButton() {
|
export function AddGroupButton() {
|
||||||
const [popupVisible, setPopupVisible] = React.useState(false)
|
const [popupVisible, setPopupVisible] = React.useState(false)
|
||||||
@@ -48,7 +49,7 @@ function Popup({ open, onClose }: {
|
|||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
<DialogFooter className='!justify-start !flex-row mt-3 gap-3'>
|
<DialogFooter className='!justify-start !flex-row mt-3 gap-3'>
|
||||||
<Link href='https://t.me/ilyakm'>
|
<Link href={TELEGRAM_CONTACT_URL}>
|
||||||
<Button tabIndex={-1} className='gap-3'><BsTelegram /> Мой Telegram</Button>
|
<Button tabIndex={-1} className='gap-3'><BsTelegram /> Мой Telegram</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { NextSerialized, nextDeserialized, nextSerialized } from '@/app/utils/da
|
|||||||
import { NavBar } from '@/widgets/navbar'
|
import { NavBar } from '@/widgets/navbar'
|
||||||
import { LastUpdateAt } from '@/entities/last-update-at'
|
import { LastUpdateAt } from '@/entities/last-update-at'
|
||||||
import { groups } from '@/shared/data/groups'
|
import { groups } from '@/shared/data/groups'
|
||||||
|
import { SITE_URL } from '@/shared/constants/urls'
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { getDayOfWeek } from '@/shared/utils'
|
import { getDayOfWeek } from '@/shared/utils'
|
||||||
@@ -47,7 +48,7 @@ export default function HomePage(props: NextSerialized<PageProps>) {
|
|||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{`Группа ${group.name} — Расписание занятий в Колледже Связи`}</title>
|
<title>{`Группа ${group.name} — Расписание занятий в Колледже Связи`}</title>
|
||||||
<link rel="canonical" href={`https://kspsuti.ru/${group.id}`} />
|
<link rel="canonical" href={`${SITE_URL}/${group.id}`} />
|
||||||
<meta name="description" content={`Расписание занятий группы ${group.name} на неделю в Колледже Связи ПГУТИ. Расписание пар, материалы для подготовки и изменения в расписании.`} />
|
<meta name="description" content={`Расписание занятий группы ${group.name} на неделю в Колледже Связи ПГУТИ. Расписание пар, материалы для подготовки и изменения в расписании.`} />
|
||||||
<meta property="og:title" content={`Группа ${group.name} — Расписание занятий в Колледже Связи`} />
|
<meta property="og:title" content={`Группа ${group.name} — Расписание занятий в Колледже Связи`} />
|
||||||
<meta property="og:description" content={`Расписание занятий группы ${group.name} на неделю в Колледже Связи ПГУТИ. Расписание пар, материалы для подготовки и изменения в расписании.`} />
|
<meta property="og:description" content={`Расписание занятий группы ${group.name} на неделю в Колледже Связи ПГУТИ. Расписание пар, материалы для подготовки и изменения в расписании.`} />
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { ISitemapField, getServerSideSitemapLegacy } from 'next-sitemap'
|
import { ISitemapField, getServerSideSitemapLegacy } from 'next-sitemap'
|
||||||
import { GetServerSideProps } from 'next'
|
import { GetServerSideProps } from 'next'
|
||||||
import { groups } from '@/shared/data/groups'
|
import { groups } from '@/shared/data/groups'
|
||||||
|
import { SITEMAP_SITE_URL } from '@/shared/constants/urls'
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
||||||
const siteURL = 'https://kspsuti.ru'
|
|
||||||
|
|
||||||
const fields = Object.keys(groups).map<ISitemapField>(group => (
|
const fields = Object.keys(groups).map<ISitemapField>(group => (
|
||||||
{
|
{
|
||||||
loc: `${siteURL}/${group}`,
|
loc: `${SITEMAP_SITE_URL}/${group}`,
|
||||||
changefreq: 'weekly',
|
changefreq: 'weekly',
|
||||||
priority: 0.8
|
priority: 0.8
|
||||||
}
|
}
|
||||||
|
|||||||
19
src/shared/constants/urls.ts
Normal file
19
src/shared/constants/urls.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* URL constants used throughout the application
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Site URLs
|
||||||
|
export const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://schedule.itlxrd.space'
|
||||||
|
export const SITEMAP_SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://schedule.itlxrd.space'
|
||||||
|
|
||||||
|
// External service URLs
|
||||||
|
export const PROXY_URL = process.env.PROXY_URL || 'https://lk.ks.psuti.ru'
|
||||||
|
export const KS_PSUTI_IMAGES_BASE_URL = 'https://ks.psuti.ru/images'
|
||||||
|
|
||||||
|
// Social media and external links
|
||||||
|
export const GITHUB_REPO_URL = 'https://github.com/kilyabin/kspguti-schedule'
|
||||||
|
export const TELEGRAM_CONTACT_URL = 'https://t.me/ilyakm'
|
||||||
|
|
||||||
|
// Teacher photos base URL
|
||||||
|
export const TEACHER_PHOTOS_BASE_URL = `${KS_PSUTI_IMAGES_BASE_URL}/stories`
|
||||||
|
|
||||||
@@ -9,6 +9,7 @@ import { FaGithub } from 'react-icons/fa'
|
|||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import { NavContext, NavContextProvider } from '@/shared/context/nav-context'
|
import { NavContext, NavContextProvider } from '@/shared/context/nav-context'
|
||||||
import { groups } from '@/shared/data/groups'
|
import { groups } from '@/shared/data/groups'
|
||||||
|
import { GITHUB_REPO_URL } from '@/shared/constants/urls'
|
||||||
|
|
||||||
export function NavBar({ cacheAvailableFor }: {
|
export function NavBar({ cacheAvailableFor }: {
|
||||||
cacheAvailableFor: string[]
|
cacheAvailableFor: string[]
|
||||||
@@ -51,7 +52,7 @@ export function NavBar({ cacheAvailableFor }: {
|
|||||||
<AddGroupButton />
|
<AddGroupButton />
|
||||||
</ul>
|
</ul>
|
||||||
<div className='flex gap-1 min-[500px]:gap-2'>
|
<div className='flex gap-1 min-[500px]:gap-2'>
|
||||||
<Link href='https://github.com/kilyabin/kspguti-schedule' target='_blank' rel='nofollower noreferrer'>
|
<Link href={GITHUB_REPO_URL} target='_blank' rel='nofollower noreferrer'>
|
||||||
<Button variant='outline' size='icon' tabIndex={-1}>
|
<Button variant='outline' size='icon' tabIndex={-1}>
|
||||||
<FaGithub />
|
<FaGithub />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user