code:
extends ../layout.pug

block head
	title #{__('Account')}

block content
	.board-header
		h1.board-title #{__(`Welcome, %s`, user.username)}
	br
	hr(size=1)
	h4.no-m-p #{__('General')}:
	ul
		if !user.twofactor && !user.web3
			li.bold: a(href='/twofactor.html') #{__('Setup 2FA (TOTP)')}
		if permissions.get(Permissions.CREATE_BOARD)
			li: a(href='/create.html') #{__('Create a board')}
		if permissions.get(Permissions.CREATE_ACCOUNT)
			li: a(href='/register.html') #{__('Register an account')}
		li: a(href='/changepassword.html') #{__('Change password')}
		li: a(href='/mypermissions.html') #{__('My permissions')}
		li: a(href='/sessions.html') #{__('Active sessions')}
	form(action='/forms/logout' method='post')
		input(type='submit' value=__('Log out'))

	if permissions.hasAny(Permissions.MANAGE_GLOBAL_GENERAL, Permissions.MANAGE_GLOBAL_BANS, Permissions.MANAGE_GLOBAL_BOARDS, Permissions.MANAGE_GLOBAL_LOGS, Permissions.MANAGE_GLOBAL_ACCOUNTS, Permissions.MANAGE_GLOBAL_NEWS, Permissions.MANAGE_GLOBAL_SETTINGS)
		hr(size=1)
		h4.no-m-p #{__('Global Management')}:
		ul
			li
				if permissions.get(Permissions.MANAGE_GLOBAL_GENERAL)
					a(href=`/globalmanage/recent.html`) #{__('Recent')}
					|
					a(href=`/globalmanage/reports.html`) #{__('Reports')}
						if globalReportCount > 0
							b  (#{globalReportCount})
				if permissions.get(Permissions.MANAGE_GLOBAL_BANS)
					|
					a(href=`/globalmanage/bans.html`) #{__('Bans')}
				if permissions.get(Permissions.MANAGE_GLOBAL_BOARDS)
					|
					a(href=`/globalmanage/boards.html`) #{__('Boards')}
				if permissions.get(Permissions.MANAGE_GLOBAL_LOGS)
					|
					a(href=`/globalmanage/globallogs.html`) #{__('Logs')}
				if permissions.get(Permissions.MANAGE_GLOBAL_ACCOUNTS)
					|
					a(href=`/globalmanage/accounts.html`) #{__('Accounts')}
				if permissions.get(Permissions.MANAGE_GLOBAL_ROLES)
					|
					a(href=`/globalmanage/roles.html`) #{__('Roles')}
				if permissions.get(Permissions.MANAGE_GLOBAL_NEWS)
					|
					a(href=`/globalmanage/news.html`) #{__('News')}
				if permissions.get(Permissions.MANAGE_GLOBAL_SETTINGS)
					|
					a(href=`/globalmanage/filters.html`) #{__('Filters')}
				if permissions.get(Permissions.MANAGE_GLOBAL_SETTINGS)
					|
					a(href=`/globalmanage/settings.html`) #{__('Global Settings')}

	hr(size=1)
	h4.no-m-p #{__('Boards you own')}:
	if user.ownedBoards && user.ownedBoards.length > 0
		ul
			for b in user.ownedBoards
				li
					a(href=`/${b}/index.html`) /#{b}/
					|  -
					a(href=`/${b}/manage/index.html`) #{__('Mod Index')}
					|
					a(href=`/${b}/manage/catalog.html`) #{__('Mod Catalog')}
					|
					a(href=`/${b}/manage/recent.html`) #{__('Recent')}
					|
					a(href=`/${b}/manage/reports.html`) #{__('Reports')}
						if boardReportCountMap[b]
							b  (#{boardReportCountMap[b]})
					|
					a(href=`/${b}/manage/bans.html`) #{__('Bans')}
					|
					a(href=`/${b}/manage/logs.html`) #{__('Logs')}
					|
					a(href=`/${b}/manage/filters.html`) #{__('Filters')}
					|
					a(href=`/${b}/manage/settings.html`) #{__('Settings')}
					|
					a(href=`/${b}/manage/assets.html`) #{__('Assets')}
					|
					a(href=`/${b}/manage/custompages.html`) #{__('Custom Pages')}
					|
					a(href=`/${b}/manage/staff.html`) #{__('Staff')}
	else
		p #{__('Nothing')}

	hr(size=1)
	h4.no-m-p #{__('Boards you are staff on')}:
	if user.staffBoards && user.staffBoards.length > 0
		ul
			for b in user.staffBoards
				li
					if permissions.get(Permissions.MANAGE_BOARD_GENERAL) || boardPermissions[b].get(Permissions.MANAGE_BOARD_GENERAL)
						a(href=`/${b}/index.html`) /#{b}/
						|  -
						a(href=`/${b}/manage/index.html`) #{__('Mod Index')}
						|
						a(href=`/${b}/manage/catalog.html`) #{__('Mod Catalog')}
						|
						a(href=`/${b}/manage/recent.html`) #{__('Recent')}
						|
						a(href=`/${b}/manage/reports.html`) #{__('Reports')}
							if boardReportCountMap[b]
								b  (#{boardReportCountMap[b]})
					if permissions.get(Permissions.MANAGE_BOARD_BANS) || boardPermissions[b].get(Permissions.MANAGE_BOARD_BANS)
						|
						a(href=`/${b}/manage/bans.html`) #{__('Bans')}
					if permissions.get(Permissions.MANAGE_BOARD_LOGS) || boardPermissions[b].get(Permissions.MANAGE_BOARD_LOGS)
						|
						a(href=`/${b}/manage/logs.html`) #{__('Logs')}
					if permissions.get(Permissions.MANAGE_BOARD_SETTINGS) || boardPermissions[b].get(Permissions.MANAGE_BOARD_SETTINGS)
						|
						a(href=`/${b}/manage/settings.html`) #{__('Settings')}
					if permissions.get(Permissions.MANAGE_BOARD_CUSTOMISATION) || boardPermissions[b].get(Permissions.MANAGE_BOARD_CUSTOMISATION)
						|
						a(href=`/${b}/manage/assets.html`) #{__('Assets')}
					if permissions.get(Permissions.MANAGE_BOARD_CUSTOMISATION) || boardPermissions[b].get(Permissions.MANAGE_BOARD_CUSTOMISATION)
						|
						a(href=`/${b}/manage/custompages.html`) #{__('Custom Pages')}
					if permissions.get(Permissions.MANAGE_BOARD_STAFF) || boardPermissions[b].get(Permissions.MANAGE_BOARD_STAFF)
						|
						a(href=`/${b}/manage/staff.html`) #{__('Staff')}
	else
		p #{__('Nothing')}

	if user.staffBoards.length > 0 ||  user.ownedBoards.length > 0
		hr(size=1)
		h4.no-m-p #{__('Resign from a staff position')}:
		.form-wrapper.flexleft.mt-10
			form.form-post(action=`/forms/resign`, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				.row
					.label #{__('Boards')}
					select(name='board' size='5')
						optgroup(label=__('You own'))
							each board in user.ownedBoards
								option(value=board) #{board}
						optgroup(label=__('You moderate'))
							each board in user.staffBoards
								option(value=board) #{board}
				.row
					.label #{__("I'm sure")}
					label.postform-style.ph-5
						input(type='checkbox', name='confirm', value='true' required)
				include ../includes/forceactiontwofactor.pug
				input(type='submit', value=__('Resign'))

	hr(size=1)
	h4.no-m-p #{__('Delete your account')}:
	.form-wrapper.flexleft.mt-10
		form.form-post(action=`/forms/deleteaccount`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__("I'm sure")}
				label.postform-style.ph-5
					input(type='checkbox', name='confirm', value='true' required)
			include ../includes/forceactiontwofactor.pug
			input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/ban.pug

block head
	title #{__('Banned!')}

block content
	h1.board-title #{__('Banned!')}
	h4.board-description #{__('Bans currently in place against your IP')}:
	include ../includes/banform.pug

repo_name: Marzisoft/jschan

license: mit


code:
extends ../layout.pug
include ../mixins/boardheader.pug
include ../mixins/boardnav.pug

block head
	title /#{board._id}/ - #{__('Banners')}

block content
	+boardheader(__('Banners'))
	br
	include ../includes/stickynav.pug
	.pages
		+boardnav('banners', true, false)
	hr(size=1)
	if board.banners.length > 0
		.catalog
			each banner in board.banners
				img.board-banner(src=`/banner/${board._id}/${banner}` loading='lazy')
	else
		p #{__('Board has no custom banners.')}
	include ../includes/stickynav.pug
	hr(size=1)
	.pages
		+boardnav('banners', true, false)


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/boardnav.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/announcements.pug

block head
	title /#{board._id}/ - #{board.settings.name} - #{__n('Page %s', page)}

block content
	+boardheader(modview ? __('Mod Index') : null)
	br
	include ../includes/postform.pug
	br
	+announcements()
	include ../includes/stickynav.pug
	if modview
		+managenav('index')
	else
		.pages
			include ../includes/boardpages.pug
			+boardnav(null, false, false)
	form(action=`/forms/board/${board._id}/${modview ? 'mod' : ''}actions` method='POST' enctype='application/x-www-form-urlencoded')
		if modview
			input(type='hidden' name='_csrf' value=csrf)
		hr(size=1)
		if threads.length === 0
			p #{__('No posts.')}
			hr(size=1)
		for thread in threads
			.thread
				+post(thread, true)
				for post in thread.replies
					+post(post, true)
			hr(size=1)
		if modview
			+managenav('index')
		else
			.pages
				include ../includes/boardpages.pug
				+boardnav(null, false, false)
		if modview
			include ../includes/actionfooter_manage.pug
		else
			include ../includes/actionfooter.pug


code:
extends ../layout.pug
include ../mixins/boardtable.pug

block head
	title #{__('Board List')}

block content
	h1.board-title #{__('Board List')}
	.flexcenter.mv-10
		form.form-post(action='/boards.html' method='GET')
			input(type='hidden' value=page)
			.row.wrap.sb
				div(class=`col${enableWebring ? ' mr-5' : ''}`)
					.row
						.label #{__('Search')}
						input(type='text' name='search' value=search placeholder=__('URI or tags'))
					.row
						.label #{__('Sort')}
						select(name='sort')
							option(value='popularity') #{__('Popularity')}
							option(value='activity' selected=query.sort === 'activity') #{__('Latest Activity')}
					.row
						.label #{__('Order')}
						select(name='direction')
							option(value='desc') #{__('Descending')}
							option(value='asc' selected=query.direction === 'asc') #{__('Ascending')}
					if enableWebring
						.row
							.label #{__('Local First')}
							label.postform-style.ph-5
								input(type='checkbox', name='local_first', value='true' checked=localFirst)
				if enableWebring
					.col
						.row
							.label #{__('Sites')}
							select(name='sites' size='5' multiple)
								optgroup(label=__('Shown'))
									each site in shown
										option(value=site selected=true) #{site}
								optgroup(label=__('Not Shown'))
									each site in notShown
										option(value=site) #{site}
			input(type='submit', value=__('Filter'))
	if boards && boards.length > 0
		+boardtable(true, true)
			each board in boards
				- const path = board.webring ? board.path : `/${board._id}/index.html`;
				tr
					td
						span.left
							if board.webring === true
								span.help(title=__('Webring')) 🔗
								|
							if board.settings.sfw === true
								span.help(title=__('SFW')) 💼
								|
						a(href=path) #{board.webring ? board.siteName : ''} /#{board.webring ? board.uri : board._id}/ - #{board.settings.name}
					td #{board.settings.description || '-'}
					td #{board.pph}
					td #{board.ppd != null ? board.ppd : '-'}
					td #{board.ips}
					td #{board.sequence_value-1}
					if board.lastPostTimestamp
						td(style=`background-color: ${board.lastPostTimestamp.color}`) #{board.lastPostTimestamp.text}
					else
						td -
	.pages.text-center.mt-5.mv-0
		include ../includes/pages.pug


code:
extends ../layout.pug

block head
	title #{__('Block Bypass')}

block content
	h1.board-title #{__('Block Bypass')}
	.form-wrapper.flex-center.mv-10
		form.form-post(action=`/forms/blockbypass?language=${encodeURIComponent(pageLanguage)}` method='POST' data-captcha-preload='true')
			.row
				.col
					include ../includes/captcha.pug
			if minimal
				input(type='hidden' name='minimal' value='1')
			input(type='submit', value=__('Submit'))
		if message
			p.title #{message}


code:
doctype html
html
	head
		meta(charset='utf-8')
		link(rel='stylesheet', href='/css/nscaptcha.css')
	body
		img.flexcenter(src='/captcha')
		form(action='/forms/newcaptcha', method='POST')
			input(type='submit' value='↻')


code:
extends ../layout.pug
include ../mixins/catalogtile.pug
include ../mixins/boardnav.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/announcements.pug

block head
	title /#{board._id}/ - #{__('Catalog')}

block content
	+boardheader(modview ? __('Mod Catalog') : __('Catalog'))
	br
	include ../includes/postform.pug
	br
	+announcements()
	include ../includes/stickynav.pug
	.wrapbar
		if modview
			+managenav('catalog')
		else
			.pages
				+boardnav('catalog', true, false)
		.pages.jsonly
			input#catalogfilter(type='text' placeholder=__('Filter'))
			select.ml-5.right#catalogsort
				option(value="" disabled selected hidden) #{__('Sort By')}
				option(value="bump") #{__('Bump Order')}
				option(value="date") #{__('Creation Date')}
				option(value="replies") #{__('Reply Count')}
	form(action=`/forms/board/${board._id}/${modview ? 'mod' : ''}actions` method='POST' enctype='application/x-www-form-urlencoded')
		if modview
			input(type='hidden' name='_csrf' value=csrf)
		hr(size=1)
		if threads.length === 0
			p #{__('No posts')}
		else
			.catalog
				for thread, i in threads
					+catalogtile(thread, i+1)
		hr(size=1)
		if modview
			+managenav('catalog')
		else
			.pages
				+boardnav('catalog', true, false)
		if modview
			include ../includes/actionfooter_manage.pug
		else
			include ../includes/actionfooter.pug


code:
extends ../layout.pug

block head
	title #{__('Change Password')}

block content
	h1.board-title #{__('Change Password')}
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/changepassword' method='POST' data-captcha-preload='true')
			.row
				.label #{__('Username')}
				input(type='text', name='username', maxlength='50' required)
			.row
				.label #{__('Existing Password')}
				input(type='password', name='password', maxlength='100' required)
			.row
				.label #{__('New Password')}
				input(type='password', name='newpassword', maxlength='100' required)
			.row
				.label #{__('Confirm New Password')}
				input(type='password', name='newpasswordconfirm', maxlength='100' required)
			.row
				.label #{__('2FA Code')}
				input(type='number' name='twofactor' placeholder=__('if enabled'))
			if captchaOptions.type === 'text'
				include ../includes/captchasidelabel.pug
			else
				include ../includes/captchafieldrow.pug
			input(type='submit', value=__('Change Password'))
		p: a(href='/login.html') #{__('Login')}
		p: a(href='/register.html') #{__('Register')}


code:
extends ../layout.pug

block head
	title #{__('Create Board')}

block content
	h1.board-title #{__('Create Board')}
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/create' method='POST' data-captcha-preload='true')
			.row
				.label #{__('URI e.g. /uri/')}
				input(type='text', name='uri', maxlength=globalLimits.fieldLength.uri pattern='[a-zA-Z0-9]+' required title=__('alphanumeric only'))
			.row
				.label #{__('Name')}
				input(type='text', name='name', maxlength=globalLimits.fieldLength.boardname required)
			.row
				.label #{__('Description')}
				input(type='text', name='description', maxlength=globalLimits.fieldLength.description)
			.row
				.label #{__('Tags')}
				textarea(name='tags' placeholder=__('Newline separated, max 10'))
			if captchaOptions.type === 'text'
				include ../includes/captchasidelabel.pug
			else
				include ../includes/captchafieldrow.pug
			input(type='submit', value=__('Create'))


code:
extends ../layout.pug
include ../mixins/custompage.pug

block head
	title /#{board._id}/ - #{customPage.title}

block content
	.board-header
		a.no-decoration(href=`/${board._id}/index.html`)
			h1.board-title /#{board._id}/ - #{customPage.title}
	include ../includes/stickynav.pug
	+custompage(customPage)


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Edit Account')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('accounts', true)
	hr(size=1)
	h4.mv-5 Edit account permissions for: "#{accountUsername}"
	- const jsonPermissions = accountPermissions.toJSON();
	.form-wrapper.flexleft
		form(action=`/forms/global/editaccount` method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='username' value=accountUsername)
			include ../includes/globalpermissionsform.pug
			hr(size=1)
			h4.mv-5 #{__('Or, apply a role')}:
			.row
				.label Role
				select(name='template')
					option(disabled selected) #{__('None')}
					//- limiting which ones atm
					option(value=roles.ANON.base64) #{__('Regular User')}
					option(value=roles.BOARD_STAFF.base64) #{__('Global Board Staff')}
					option(value=roles.BOARD_OWNER.base64) #{__('Global Board Owner')}
					option(value=roles.GLOBAL_STAFF.base64) #{__('Global Staff')}
					option(value=roles.ADMIN.base64) #{__('Admin')}
			input(type='submit', value=__('Apply'))


code:
extends ../layout.pug
include ../mixins/boardheader.pug
include ../mixins/managenav.pug

block head
	title /#{board._id}/ - #{__('Edit Custom Page')}

block content
	+boardheader(__('Edit Custom Page'))
	br
	+managenav('custompages', true)
	hr(size=1)
	include ../includes/stickynav.pug
	.form-wrapper.flex-center.mv-10
		form.form-post(action=`/forms/board/${board._id}/editcustompage` method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='page_id' value=page._id)
			.row
				.label #{__('.html name')}
				input(type='text' name='page' pattern='[a-zA-Z0-9-_]+' placeholder=__('a-zA-Z0-9-_ only') value=page.page required)
			.table-container.flex-center.mv-5
				table
					tr
						th
							input.edit.left(type='text' name='title' value=page.title required)
							- const pageDate = new Date(page.date);
							time.right.reltime(datetime=pageDate.toISOString()) #{pageDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
					tr
						td

							textarea.edit.fw(name='message' rows='10' placeholder=__('Supports post styling') required) #{page.message.raw}
			input(type='submit', value=__('Save'))


code:
extends ../layout.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Edit Filter')}

block content
	+boardheader(__('Edit Filter'))
	br
	+managenav('filters', true)
	hr(size=1)
	h4.no-m-p
		| #{__('Edit Filter')}
		|  (
		a(href='/faq.html#filters') #{__('Filters FAQ')}
		| ):
	.form-wrapper.flex-center.mv-10
		form.form-post(action=`/forms/board/${board._id}/editfilter` method='POST')
			include ../includes/filtereditform.pug


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Edit News')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('news', true)
	hr(size=1)
	h4.no-m-p #{__('Edit Newspost')}:
	include ../includes/stickynav.pug
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/global/editnews' method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='news_id' value=news._id)
			.table-container.flex-center.mv-5
				table
					tr
						th
							input.edit.left(type='text' name='title' value=news.title required)
							- const newsDate = new Date(news.date);
							time.right.reltime(datetime=newsDate.toISOString()) #{newsDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
					tr
						td
							textarea.edit.fw(name='message' rows='10' placeholder=__('Supports post styling') required) #{news.message.raw}
			input(type='submit', value=__('Save'))


code:
extends ../layout.pug

block head
	title #{__('Edit Post')}

block content
	h1.board-title #{__('Edit Post')}
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/editpost' method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='referer' value=referer)
			input(type='hidden' name='board' value=post.board)
			input(type='hidden' name='postId' value=post.postId)
			.anchor(id=post.postId)
			div(class=`mv-5 post-container ${post.thread || ban === true ? '' : 'op'}` data-board=post.board data-post-id=post.postId data-user-id=post.userId)
				- const postURL = `/${post.board}/thread/${post.thread || post.postId}.html`;
				.post-info
					span.noselect
						label
							if !post.thread
								include ../includes/posticons.pug
							input.edit.post-subject(value=post.subject placeholder=__('Subject') type='text' name='subject' maxlength=globalLimits.fieldLength.subject)
							input.edit.post-name(value=post.email type='text' name='email' placeholder=__('Email') maxlength=globalLimits.fieldLength.email)
							input.edit.post-name(type='text' name='name' placeholder=__('Name') maxlength=globalLimits.fieldLength.name value=post.name+(post.capcode || ''))
						if post.country && post.country.code
							include ../includes/postflag.pug
						if post.tripcode
							span.post-tripcode #{post.tripcode}
							|
						if post.capcode
							span.post-capcode #{post.capcode}
							|
						- const postDate = new Date(post.date);
						time.post-date.reltime(datetime=postDate.toISOString()) #{postDate.toLocaleString(pageLanguage, { hourCycle:'h23' })}
						|
						if post.userId
							span.user-id(style=`background-color: #${post.userId}`) #{post.userId}
							|
					span.post-links
						a.noselect.no-decoration(href=`${postURL}#${post.postId}`) #{__('No.')}
						span.post-quoters
							a.no-decoration(href=`${postURL}#postform`) #{post.postId}
				.post-data
					pre.post-message
						textarea.edit.fw(name='message' rows='15' placeholder=__('Message')) #{post.nomarkup}
					if post.banmessage
						p.ban
							span.message #{__('USER WAS BANNED FOR THIS POST')}
							|
							span.reason(data-reason=post.banmessage) #{post.banmessage}
			label.mt-5
				input.post-check(type='checkbox', name='hide_name' value='1')
				| #{__('Hide Username')}
			label.mv-5
				input(type='text', name='log_message', placeholder=__('Modlog message') autocomplete='off')
			input(type='submit', value=__('Save'))


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Edit Role')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('roles', true)
	hr(size=1)
	h4.mv-5 #{__('Edit role %s', __(roleNameMap[role.name]))}
	- const jsonPermissions = rolePermissions.toJSON();
	.form-wrapper.flexleft
		form(action=`/forms/global/editrole` method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='roleid' value=role._id)
			include ../includes/globalpermissionsform.pug


code:
extends ../layout.pug
include ../mixins/boardheader.pug
include ../mixins/managenav.pug

block head
	title /#{board._id}/ - #{__('Edit Staff Permissions')}

block content
	+boardheader(__('Edit Staff Permissions'))
	br
	+managenav('staff', true)
	hr(size=1)
	h4.mv-5 #{__('Edit board permissions for "%s"', staffUsername)}
		|
		if permissions.get(Permissions.MANAGE_GLOBAL_ACCOUNTS)
			|
			a(href=`/globalmanage/editaccount/${staffUsername}.html`) [#{__('Edit Account Permissions')}]
	- const jsonPermissions = staffPermissions.toJSON();
	.form-wrapper.flexleft
		form(action=`/forms/board/${board._id}/editstaff` method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='username' value=staffUsername)
			include ../includes/staffpermissionsform.pug


code:
extends ../layout.pug

block content
	h1 #{__('Internal Server Error')}


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Edit Filter')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('filters', true)
	hr(size=1)
	h4.no-m-p
		| #{__('Edit Filter')}
		|  (
		a(href='/faq.html#filters') #{__('Filters FAQ')}
		| ):
	include ../includes/stickynav.pug
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/global/editfilter' method='POST')
			include ../includes/filtereditform.pug


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Accounts')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('accounts')
	hr(size=1)
	.form-wrapper.flexleft
		h4.no-m-p #{__('Search')}:
		form.form-post.mv-5(action=`/globalmanage/accounts.html` method='GET')
			input(type='hidden' value=page)
			.row
				.label #{__('Username')}
				input(type='text' name='username' value=username)
			.row
				.label #{__('Board URI')}
				input(type='text' name='uri' value=uri)
			input(type='submit', value=__('Filter'))
		h4.mv-5 #{__('Accounts')}:
		if accounts && accounts.length > 0
			form.form-post.nogrow(action=`/forms/global/deleteaccounts` method='POST' enctype='application/x-www-form-urlencoded')
				input(type='hidden' name='_csrf' value=csrf)
				.table-container.flex-left.text-center
					table.accounttable
						tr
							th
							th #{__('Username')}
							th #{__('Own Boards')}
							th #{__('Staff Boards')}
							th #{__('Last Active')}
							th #{__('2FA')}
							th #{__('Role')}
							th #{__('Permissions')}
						for account in accounts
							tr
								td
									input.postform-style(type='checkbox', name='checkedaccounts' value=account._id)
									|
									if permissions.get(Permissions.MANAGE_GLOBAL_BOARDS)
										.prev-show
											input(type='checkbox', name='delete_owned_boards' value=account._id)
											| #{__('Delete all owned boards')}:
								td #{account._id}
								td
									if account.ownedBoards.length > 0
										for b in account.ownedBoards
											a(href=`/${b}/index.html`) /#{b}/
											|
									else
										| -
								td
									if account.staffBoards.length > 0
										for b in account.staffBoards
											a(href=`/${b}/index.html`) /#{b}/
											|
									else
										| -
								td
									if account.lastActiveDate
										time.reltime(datetime=account.lastActiveDate.toISOString()) #{account.lastActiveDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
									else
										| -
								td
									if account.twofactor
										| ✓
									else
										| -
								td #{rolePermissionMap[account.permissions.toString('base64')] || __('Custom')}
								td
									if account._id !== user.username
										a(href=`/globalmanage/editaccount/${account._id}.html`) [#{__('Edit')}]
									else
										a(href=`/mypermissions.html`) [#{__('View')}]
				.pages.mv-5
					include ../includes/pages.pug
				h4.mv-5 #{__('Delete Selected')}:
				include ../includes/forceactiontwofactor.pug
				input(type='submit', value=__('Delete'))
		else
			p #{__('No results.')}


code:
extends ../layout.pug
include ../mixins/ban.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Bans')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('bans')
	hr(size=1)
	h4.no-m-p #{__('Global Bans & Appeals')}:
	form(action=`/forms/global/editbans` method='POST' enctype='application/x-www-form-urlencoded')
		include ../includes/managebanform.pug


code:
extends ../layout.pug
include ../mixins/ban.pug
include ../mixins/globalmanagenav.pug
include ../mixins/boardtable.pug

block head
	title #{__('Boards')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('boards')
	hr(size=1)
	h4.text-center.no-m-p #{__('Filter')}:
	.flexcenter.mv-10
		form.form-post(action='/globalmanage/boards.html' method='GET')
			input(type='hidden' value=page)
			.row.wrap.sb
				.col.mr-5
					.row
						.label #{__('Search')}
						input(type='text' name='search' value=search placeholder=__('URI or tags'))
					.row
						.label #{__('Sort')}
						select(name='sort')
							option(value='popularity') #{__('Popularity')}
							option(value='activity' selected=query.sort === 'activity') #{__('Latest Activity')}
					.row
						.label #{__('Order')}
						select(name='direction')
							option(value='desc') #{__('Descending')}
							option(value='asc' selected=query.direction === 'asc') #{__('Ascending')}
				.col
					.row
						.label #{__('Unlisted')}
						label.postform-style.ph-5
							input(type='checkbox', name='filter_unlisted', value='1' checked=(query.filter_unlisted != null))
					.row
						.label #{__('SFW')}
						label.postform-style.ph-5
							input(type='checkbox', name='filter_sfw', value='1' checked=(query.filter_sfw != null))
					.row
						.label #{__('Abandoned')}
						label.postform-style.ph-5
							input(type='checkbox', name='filter_abandoned', value='1' checked=(query.filter_abandoned != null))
			input(type='submit', value='Filter')
	if localBoards && localBoards.length > 0
		h4.text-center.mv-10 #{__('Board List')}:
		+boardtable(true, true, permissions.get(Permissions.GLOBAL_MANAGE_ACCOUNTS))
			each board in localBoards
				tr
					td
						span.left
							if board.settings.sfw === true
								span.help(title=__('SFW')) 💼
								|
							if board.settings.unlistedLocal === true
								span.help(title=__('Unlisted')) 👁
								|
							if !board.owner
								span.help(title=__('Abandoned')) 🏚
								|
						a(href=`/${board._id}/manage/index.html`) /#{board._id}/ - #{board.settings.name}
					if permissions.get(Permissions.GLOBAL_MANAGE_ACCOUNTS)
						if board.owner
							td: a(href=`/globalmanage/accounts.html?username=${board.owner}`) #{board.owner}
						else
							td -
					td #{board.settings.description}
					td.nobreak #{board.pph}
					td.nobreak #{board.ppd}
					td.nobreak #{board.ips}
					td.nobreak #{board.sequence_value-1}
					if board.lastPostTimestamp
						td.nobreak(style=`background-color: ${board.lastPostTimestamp.color}`) #{board.lastPostTimestamp.text}
					else
						td -
	.pages.text-center.mt-5.mv-0
		include ../includes/pages.pug


code:
extends ../layout.pug
include ../mixins/filter.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Filters')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('filters')
	hr(size=1)
	h4.no-m-p
		| #{__('Add Filter')}
		|  (
		a(href='/faq.html#filters') #{__('Filters FAQ')}
		| ):
	.form-wrapper.flexleft
		form.form-post(action='/forms/global/addfilter', enctype='application/x-www-form-urlencoded', method='POST')
			include ../includes/filternewform.pug
	if filters.length > 0
		hr(size=1)
		h4.no-m-p #{__('Manage Filters')}:
			.form-wrapper.flexleft
				form.form-post(action='/forms/global/deletefilter', enctype='application/x-www-form-urlencoded', method='POST')
					input(type='hidden' name='_csrf' value=csrf)
					.table-container.mv-5.horscroll
						table
							tr
								th
								th #{__('Filters')}
								th #{__('Strict Filtering')}
								th #{__('Filter Mode')}
								th #{__('Block/Ban Message')}
								th #{__('Filter Auto Ban Duration')}
								th #{__('Filter Bans Appealable')}
								th #{__('Replace Text')}
								th #{__('Edit')}
							each f in filters
								+filter(f, true)
					input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/ban.pug
include ../mixins/globalmanagenav.pug
include ../mixins/postlink.pug

block head
	title #{__('Logs')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('logs')
	hr(size=1)
	.form-wrapper.flexleft
		h4.no-m-p #{__('Search')}:
		form.form-post.mv-5(action=`/globalmanage/globallogs.html` method='GET')
			input(type='hidden' value=page)
			.row
				.label #{__('Board URI')}
				input(type='text' name='uri' value=uri)
			.row
				.label #{__('Username')}
				input(type='text' name='username' value=username)
			.row
				.label #{__('IP')}
				input(type='text' name='ip' value=ip)
			input(type='submit', value=__('Filter'))
		h4.no-m-p #{__('Global Logs')}:
		if logs && logs.length > 0
			.table-container.flex-center.mv-10.text-center
				table.fw
						tr
							th #{__('Date')}
							th #{__('Board')}
							th #{__('User')}
							th #{__('IP')}
							th #{__('Actions')}
							th #{__('Links')}
							th #{__('Log Message')}
						for log in logs
							tr
								- const logDate = new Date(log.date);
								td: time.reltime(datetime=logDate.toISOString()) #{logDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
								td
									if log.board
										a(href=`/${log.board}/index.html`) /#{log.board}/
										|
										a(href=`?uri=${log.board}`) [+]
									else
										| -
								td
									if log.user !== __('Unregistered User')
										a(href=`accounts.html?username=${log.user}`) #{log.user}
									else
										| #{log.user}
									|
									a(href=`?username=${log.user}`) [+]
								td
									- const logIp = viewRawIp === true ? log.ip.raw : log.ip.cloak;
									a(href=`recent.html?ip=${encodeURIComponent(logIp)}`) #{logIp}
									|
									a(href=`?ip=${encodeURIComponent(logIp)}`) [+]
								td #{log.actions.map(a => __(a))}
								td
									if log.showLinks
										for postLink in log.postLinks
											+postlink(log, postLink, true)
											|
									else
										| #{log.postLinks.map(l => l.postId)}
								td #{log.message || '-'}
			.pages.mv-5
				include ../includes/pages.pug
		else
			p #{__('No Logs.')}


code:
extends ../layout.pug
include ../mixins/newspost.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('News')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('news')
	hr(size=1)
	h4.no-m-p #{__('Add News')}:
	.form-wrapper.flexleft
		form.form-post(action=`/forms/global/addnews`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__('Title')}
				input(type='text' name='title' required)
			.row
				.label #{__('Message')}
				textarea(name='message' rows='10' placeholder=__('Supports post styling') required)
			input(type='submit', value=__('Submit'))
	if news.length > 0
		hr(size=1)
		h4.no-m-p #{__('Manage News')}:
		.form-wrapper.flexleft
			form.form-post(action=`/forms/global/deletenews`, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				each post in news
					+newspost(post, true)
				if news.length === 1
					.anchor
				input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug
include ../mixins/post.pug

block head
	title #{__('Recent Posts')}

block content
	h1.board-title #{__('Global Management')}
	br
	.wrapbar
		+globalmanagenav('recent')
		if page === 1 && !ip
			.jsonly#livetext(data-view-raw-ip=(viewRawIp?'true':'false') data-room=`globalmanage-recent-${viewRawIp === true ? 'raw' : 'hashed'}`)
				.dot#livecolor
				|  #{__('Connecting...')}
				input.postform-style.ml-5.di#updatepostsbutton(type='button' value=__('Update'))
	form(action=`/forms/global/actions` method='POST' enctype='application/x-www-form-urlencoded')
		input(type='hidden' name='_csrf' value=csrf)
		if posts.length === 0
			hr(size=1)
			p #{__('No posts.')}
		else
			hr(size=1)
			if ip
				h4.no-m-p #{__(`Global post history for %s`, ip)}
				hr(size=1)
			for p in posts
				.thread
					+post(p, false, false, true)
				hr(size=1)
			.pages.mv-5
				include ../includes/pages.pug
			include ../includes/actionfooter_globalmanage.pug


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Reports')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('reports')
	form(action=`/forms/global/actions` method='POST' enctype='application/x-www-form-urlencoded')
		if reports.length === 0
			hr(size=1)
			p #{__('No reports.')}
		else
			input(type='hidden' name='_csrf' value=csrf)
			hr(size=1)
			if ip
				h4.no-m-p #{__('Reports against or by ip %s', ip)}
				hr(size=1)
			for report in reports
				.thread
					+post(report, false, false, true)
				hr(size=1)
			.pages.mv-5
				include ../includes/pages.pug
			include ../includes/actionfooter_globalmanage.pug


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Roles')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('roles')
	hr(size=1)
	h4.mv-5 #{__('Roles')}:
	.table-container.flex-left.text-center
		table
			tr
				th #{__('Role')}
				th #{__('Permissions')}
			for role in allRoles
				tr
					td(title=`Raw permissions: ${role.permissions.toString('base64')}`) #{roleNameMap[role.name]}
					td: a(href=`/globalmanage/editrole/${role._id}.html`) [#{__('Edit')}]


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Settings')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('settings')
	hr(size=1)
	h4.no-m-p #{__('Settings')}:
	.form-wrapper.flexleft
		form.form-post(action=`/forms/global/settings`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.mv-10
				.sm#tab-1
					.sm#tab-2
						.sm#tab-3
							.sm#tab-4
								.sm#tab-5
									.sm#tab-6
										.sm#tab-7
											.sm#tab-8
												.sm#tab-9
													.sm#tab-10
														.sm#tab-11
															.tabbed-area
																include ../includes/globalmanagesettings.pug
			include ../includes/forceactiontwofactor.pug
			input.row(type='submit', value=__('Save settings'))
	hr(size=1)
	h4.no-m-p #{__('Delete board')}:
	.form-wrapper.flexleft.mt-10
		form.form-post(action=`/forms/global/deleteboard`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__('Board URI')}
				input(type='text' name='uri' required)
			.row
				.label #{__("I'm sure")}
				label.postform-style.ph-5
					input(type='checkbox', name='confirm', value='true' required)
			input(type='submit', value=__('Submit'))
	hr(size=1)
	h4.no-m-p #{__('Clear All')}:
	.form-wrapper.flexleft.mt-10
		form.form-post(action=`/forms/global/clear`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__('Table')}
				select(name='table')
					option(value='sessions') #{__('Login Sessions')}
					option(value='blockbypass') #{__('Block Bypasses')}
			.row
				.label #{__("I'm sure")}
				label.postform-style.ph-5
					input(type='checkbox', name='confirm', value='true' required)
			include ../includes/forceactiontwofactor.pug
			input(type='submit', value=__('Submit'))


code:
extends ../layout.pug
include ../mixins/boardtable.pug

block head
	title #{meta.siteName}

block content
	h1.board-title #{meta.siteName}
	.table-container.flex-center.mv-10.text-center
		table
			tr
				th.alt #{__('Welcome')}
			tr
				td
					pre.no-m-p
						| The site administrator should edit views/pages/home.pug, then run "pm2 reload all" and "gulp html" to customise this page.
	if recentNews && recentNews.length > 0
		.table-container.flex-center.mv-10
			table.newstable
				tr
					th(colspan=3) #{__('Latest News')}
				each post in recentNews
					tr
						td
							a.left(href=`/news.html#${post._id}`) #{post.title}
						td
							p.no-m-p #{`${post.message.raw.substring(0,50)}${post.message.raw.length > 50 ? '...' : ''}`}
						td
							- const newsDate = new Date(post.date);
							time.right.reltime(datetime=newsDate.toISOString()) #{newsDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
	if hotThreads && hotThreads.length > 0
		.table-container.flex-center.mv-10
			table#hotposts
				tr(colspan=3)
				each post, i in hotThreads
					tr
						td.text-center
							span.help(title=__('Hot Thread (%s)', post.score.toFixed(1))) 🔥
							|  #{post.replyposts}
						td
							- const threadLink = `/${post.board}/thread/${post.postId}.html#${post.postId}`;
							a.quote(href=threadLink)
								if post.subject
									| #{post.subject.substring(0,30)}#{post.subject.length > 30 ? '...' : ''}
									if post.nomarkup
										|  -
								if post.nomarkup
									| #{post.nomarkup.substring(0,40)}#{post.nomarkup.length > 40 ? '...' : ''}
								if !post.nomarkup && !post.subject
									| >>>/#{post.board}/#{post.postId}
						td
							- const postedDate = new Date(post.date);
							time.right.reltime(datetime=postedDate.toISOString()) #{postedDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
	if boards && boards.length > 0
		+boardtable(true, false)
			each board in boards
				tr
					td
						if board.settings.sfw === true
							span.left
								span.help(title=__('SFW')) 💼
								|
						a(href=`/${board._id}/index.html`) /#{board._id}/ - #{board.settings.name}
					td #{board.settings.description}
					td.nobreak #{board.pph}
					td.nobreak #{board.ppd}
					td.nobreak #{board.ips}
					td.nobreak #{board.sequence_value-1}
			if localStats.total-localStats.unlisted > boards.length
				tr
					td(colspan=6)
						a.bold(href='/boards.html') More Boards
		.table-container.flex-center.mv-10.text-center
			table(style='max-width:450px')
				tr
					th #{__('Local Stats')}
				tr
					td
						pre.no-m-p
							| #{__('There are currently %s public boards, %s in total. Sitewide, %s posts have been made in the last day, %s in the last hour, %s in total.', localStats.total-localStats.unlisted, localStats.total, localStats.ppd, localStats.pph, localStats.posts)}
							| #{__('%s files are being served, totaling %s.', fileStats.count, fileStats.totalSizeString)}
		if enableWebring === true && webringStats != null
			.table-container.flex-center.mv-10.text-center
				table(style='max-width:450px')
					tr
						th #{__('Webring Stats')}
					tr
						td
							pre.no-m-p
								| #{__('There are currently %s sites and %s boards in the known webring. Across all webring boards, %s posts have been made in the last hour, %s in total.', webringStats.sites, webringStats.total, webringStats.pph, webringStats.posts)}


code:
extends ../layout.pug

block head
	title #{__('Login')}

block content
	h1.board-title #{__('Login')}
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/login' method='POST')
			input(type='hidden' name='goto' value=goto)
			.row
				.label #{__('Username')}
				input(type='text', name='username', maxlength='50' required)
			.row
				.label #{__('Password')}
				input(type='password', name='password', maxlength='100' required)
			.row
				.label #{__('2FA Code')}
				input(type='number' name='twofactor' placeholder=__('if enabled'))
			input(type='submit', value=__('Login'))
	if enableWeb3 === true
		.jsonly.web3.mv-10
			.text-center OR
			.form-wrapper.flex-center.mv-10
				form.form-post(action='/forms/login' method='POST' data-captcha-preload='true')
					input(type='hidden' name='nonce')
					input(type='hidden' name='address')
					input(type='hidden' name='signature')
					.postform-style.dummy-link.web3-login.ct-r1.ph-5
						img(src='/file/metamask-fox.svg' width=24 height=24)
						| #{__('Login with MetaMask')}
	.text-center.mt-10
		p: a(href='/register.html') #{__('Register')}
		p: a(href='/changepassword.html') #{__('Change Password')}


code:
extends ../layout.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/fileform.pug

block head
	title /#{board._id}/ - #{__('Assets')}

block content
	+boardheader(__('Assets'))
	br
	+managenav('assets')
	hr(size=1)
	+fileform('banner', globalLimits.bannerFiles.max, globalLimits.bannerFiles.total,
		`/forms/board/${board._id}/addbanners`, `/forms/board/${board._id}/deletebanners`,
		'checkedbanners', board.banners, board.banners, `/banner/${board._id}`,
		'asset-banner', false, false,
		__('Images randomly chosen and displayed at the top of most pages on the board'))
	hr(size=1)
	+fileform('flag', globalLimits.flagFiles.max, globalLimits.flagFiles.total,
		`/forms/board/${board._id}/addflags`, `/forms/board/${board._id}/deleteflags`,
		'checkedflags', Object.values(board.flags), Object.keys(board.flags),
		`/flag/${board._id}`, 'asset-flag', true, false,
		__('Flags that can be applied to posts if custom flags are enabled in board settings'))
	hr(size=1)
	+fileform('asset', globalLimits.assetFiles.max, globalLimits.assetFiles.total,
		`/forms/board/${board._id}/addassets`, `/forms/board/${board._id}/deleteassets`,
		'checkedassets', board.assets, board.assets,
		`/asset/${board._id}`, 'asset-generic', false, true,
		__('Arbitrary assets that can be used for other purposes e.g. custom CSS'))


code:
extends ../layout.pug
include ../mixins/ban.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Bans & Appeals')}

block content
	+boardheader(__('Bans'))
	br
	+managenav('bans')
	hr(size=1)
	h4.mv-5 #{__('Bans & Appeals')}:
	form(action=`/forms/board/${board._id}/editbans` method='POST' enctype='application/x-www-form-urlencoded')
		include ../includes/managebanform.pug


code:
extends ../layout.pug
include ../mixins/boardheader.pug
include ../mixins/managenav.pug
include ../mixins/custompage.pug

block head
	title /#{board._id}/ - #{__('Custom Pages')}

block content
	+boardheader(__('Custom Pages'))
	br
	+managenav('custompages')
	hr(size=1)
	h4.mv-5 #{__('Add Custom Page')}:
	.form-wrapper.flexleft
		form.form-post(action=`/forms/board/${board._id}/addcustompages`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__('.html name')}
				input(type='text' name='page' pattern='[a-zA-Z0-9-_]+' placeholder=__('a-zA-Z0-9-_ only') required)
			.row
				.label #{__('Title')}
				input(type='text' name='title' required)
			.row
				.label #{__('Message')}
				textarea(name='message' rows='10' placeholder=__('Supports post styling') required)
			input(type='submit', value=__('Submit'))
	if customPages.length > 0
		hr(size=1)
		h4.no-m-p #{__('Manage Custom Pages')}:
		.form-wrapper.flexleft
			form.form-post(action=`/forms/board/${board._id}/deletecustompages`, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				each page in customPages
					+custompage(page, true)
				if customPages.length === 1
					.anchor
				input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/filter.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Filters')}

block content
	+boardheader(__('Filters'))
	br
	+managenav('filters')
	hr(size=1)
	h4.no-m-p
		| #{__('Add Filter')}
		|  (
		a(href='/faq.html#filters') #{__('Filters FAQ')}
		| ):
	.form-wrapper.flexleft
		form.form-post(action=`/forms/board/${board._id}/addfilter`, enctype='application/x-www-form-urlencoded', method='POST')
			include ../includes/filternewform.pug
	if filters.length > 0
		hr(size=1)
		h4.no-m-p #{__('Manage Filters')}:
		.form-wrapper.flexleft
			form.form-post(action=`/forms/board/${board._id}/deletefilter`, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				.table-container.mv-5.horscroll
					table
						tr
							th
							th #{__('Filters')}
							th #{__('Strict Filtering')}
							th #{__('Filter Mode')}
							th #{__('Block/Ban Message')}
							th #{__('Filter Auto Ban Duration')}
							th #{__('Filter Bans Appealable')}
							th #{__('Replace Text')}
							th #{__('Edit')}
						each f in filters
							+filter(f)
				input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/ban.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/postlink.pug

block head
	title /#{board._id}/ - #{__('Logs')}

block content
	+boardheader(__('Logs'))
	br
	+managenav('logs')
	hr(size=1)
	.form-wrapper.flexleft
		h4.no-m-p #{__('Search')}:
		form.form-post.mv-5(action=`/${board._id}/manage/logs.html` method='GET')
			input(type='hidden' value=page)
			.row
				.label #{__('Username')}
				input(type='text' name='username' value=username)
			input(type='submit', value=__('Filter'))
		h4.no-m-p Logs:
		if logs && logs.length > 0
			.table-container.flex-center.mv-10.text-center
				table.fw
						tr
							th #{__('Date')}
							th #{__('User')}
							th #{__('IP')}
							th #{__('Actions')}
							th #{__('Links')}
							th #{__('Log Message')}
						for log in logs
							tr
								- const logDate = new Date(log.date);
								td: time.reltime(datetime=logDate.toISOString()) #{logDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
								td
									| #{log.user}
									|
									a(href=`?username=${log.user}`) [+]
								td
									- const logIp = viewRawIp === true ? log.ip.raw : log.ip.cloak;
									| #{logIp}
								td #{log.actions.map(a => __(a))}
								td
									if log.showLinks
										for postLink in log.postLinks
											+postlink(log, postLink, true)
											|
									else
										| #{log.postLinks.map(l => l.postId)}
								td #{log.message || '-'}
			.pages.mv-5
				include ../includes/pages.pug
		else
			p #{__('No logs.')}


code:
extends ../layout.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/mypermissions.pug

block head
	title /#{board._id}/ - #{__('My Permissions')}

block content
	+boardheader(__('My Permissions'))
	br
	+managenav('staff')
	hr(size=1)
	h4.mv-5 #{__('Board-specific permissions')}
		|
		if permissions.get(Permissions.MANAGE_BOARD_STAFF) && user.staffBoards.includes(board._id)
			|
			a(href=`/${board._id}/manage/editstaff/${user.username}.html`) [#{__('Edit')}]
	- const jsonPermissions = permissions.toJSON();
	+mypermissions(jsonPermissions, true)


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/ban.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Recent Posts')}

block content
	+boardheader(__('Recent Posts'))
	br
	.wrapbar
		+managenav('recent')
		if page === 1 && !postId && !queryIp
			.jsonly#livetext(data-view-raw-ip=(viewRawIp?'true':'false') data-room=`${board._id}-manage-recent-${viewRawIp === true ? 'raw' : 'hashed'}`)
				.dot#livecolor
				|  #{__('Connecting...')}
				input.postform-style.ml-5.di#updatepostsbutton(type='button' value=__('Update'))
	form(action=`/forms/board/${board._id}/modactions` method='POST' enctype='application/x-www-form-urlencoded')
		input(type='hidden' name='_csrf' value=csrf)
		if posts.length === 0
			hr(size=1)
			p #{__('No posts.')}
		else
			hr(size=1)
			- const ip = viewRawIp === true ? posts[0].ip.raw : posts[0].ip.cloak;
			if postId || (queryIp && queryIp === ip)
				h4.no-m-p #{__('Post history for %s', ip)}
					|
					if permissions.get(Permissions.MANAGE_GLOBAL_GENERAL)
						|
						a(href=`/globalmanage/recent.html?ip=${encodeURIComponent(ip)}`) [#{__('See Global Post History')}]
				hr(size=1)
			for p in posts
				.thread
					+post(p, true, true)
				hr(size=1)
			.pages.mv-5
				include ../includes/pages.pug
			include ../includes/actionfooter_manage.pug


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/ban.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Reports')}

block content
	+boardheader(__('Reports'))
	br
	+managenav('reports')
	hr(size=1)
	h4.no-m-p #{__('Reports')}:
	form(action=`/forms/board/${board._id}/modactions` method='POST' enctype='application/x-www-form-urlencoded')
		if reports.length === 0
			p #{__('No reports.')}
		else
			input(type='hidden' name='_csrf' value=csrf)
			for report in reports
				.thread
					+post(report, false, true)
				hr(size=1)
			include ../includes/actionfooter_manage.pug


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/ban.pug
include ../mixins/boardheader.pug
include ../mixins/managenav.pug

block head
	title /#{board._id}/ - #{__('Settings')}

block content
	+boardheader(__('Settings'))
	br
	+managenav('settings')
	if permissions.get(Permissions.MANAGE_BOARD_OWNER)
		hr(size=1)
		h4.no-m-p #{__('Transfer ownership')}:
		.form-wrapper.flexleft.mt-10
			form.form-post(action=`/forms/board/${board._id}/transfer`, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				.row
					.label #{__('New owner username')}:
					input(type='text' name='username' placeholder=board.owner required)
				input(type='submit', value=__('Submit'))
		hr(size=1)
		h4.no-m-p #{__('Delete board')}:
		.form-wrapper.flexleft.mt-10
			form.form-post(action=`/forms/board/${board._id}/deleteboard`, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				.row
					.label #{__('Board URI')}:
					input(type='text' name='uri' required)
				.row
					.label #{__("I'm sure")}
					label.postform-style.ph-5
						input(type='checkbox', name='confirm', value='true' required)
				input(type='submit', value=__('Submit'))
	hr(size=1)
	.form-wrapper.flexleft.mt-10
		form.form-post(action=`/forms/board/${board._id}/settings` method='POST' enctype='application/x-www-form-urlencoded')
			input(type='hidden' name='_csrf' value=csrf)
			.mv-10
				.sm#tab-1
					.sm#tab-2
						.sm#tab-3
							.sm#tab-4
								.sm#tab-5
									.tabbed-area
										ul.tabs.group
											li
												a(href='#tab-1') #{__('General')}
											li
												a(href='#tab-2') #{__('Posting')}
											li
												a(href='#tab-3') #{__('Files')}
											li
												a(href='#tab-4') #{__('Limits')}
											li
												a(href='#tab-5') #{__('Antispam')}
										.box-wrap
											.tab.tab-1
												.col
													.row
														.label #{__('Board name')}
														input(type='text' name='name' value=board.settings.name)
													.row
														.label #{__('Board Description')}
														input(type='text' name='description' value=board.settings.description)
													.row
														.label #{__('Tags')}
														textarea(name='tags' placeholder=__('Newline separated, max 10')) #{board.tags.join('\n')}
													.row
														.label #{__('Announcement')}
														textarea(name='announcement' placeholder=__('Supports post styling')) #{board.settings.announcement.raw}
													.row
														.label #{__('Language')}
														select(name='language')
															each language in languages
																option(value=language selected=board.settings.language === language) #{__(language)} (#{language})
													.row
														.label #{__('Theme')}
														select(name='theme')
															each theme in themes
																option(value=theme selected=board.settings.theme === theme) #{theme}
													.row
														.label #{__('Code Theme')}
														select(name='code_theme')
															each theme in codeThemes
																option(value=theme selected=board.settings.codeTheme === theme) #{theme}
													if globalLimits.customCss.enabled
														.row
															.label #{__('Custom CSS')}
															textarea(name='custom_css' placeholder=__('Test first in top-right settings if you have javascript enabled') maxlength=globalLimits.customCss.max) #{board.settings.customCss}
													.row
														.label #{__('Hide Banners')}
														label.postform-style.ph-5
															input(type='checkbox', name='hide_banners', value='true' checked=board.settings.hideBanners)
													.row
														.label #{__('IDs')}
														label.postform-style.ph-5
															input(type='checkbox', name='ids', value='true' checked=board.settings.ids)
													.row
														.label #{__('Geo Flags')}
														label.postform-style.ph-5
															input(type='checkbox', name='geo_flags', value='true' checked=board.settings.geoFlags)
													.row
														.label #{__('Custom Flags')}
														label.postform-style.ph-5
															input(type='checkbox', name='custom_flags', value='true' checked=board.settings.customFlags)
													.row
														.label #{__('Reverse Image Search Links')}
														label.postform-style.ph-5
															input(type='checkbox', name='reverse_image_search_links', value='true' checked=board.settings.reverseImageSearchLinks)
													.row
														.label #{__('External Archive Links')}
														label.postform-style.ph-5
															input(type='checkbox', name='archive_links', value='true' checked=board.settings.archiveLinks)
													.row
														.label #{__('Enable Tegaki')}
														label.postform-style.ph-5
															input(type='checkbox', name='enable_tegaki', value='true' checked=board.settings.enableTegaki)
													.row
														.label #{__('Enable Web3')}
														label.postform-style.ph-5
															input(type='checkbox', name='enable_web3', value='true' checked=board.settings.enableWeb3)
													.row
														.label #{__('SFW')}
														label.postform-style.ph-5
															input(type='checkbox', name='sfw', value='true' checked=board.settings.sfw)
													.row
														.label #{__('Unlist locally')}
														label.postform-style.ph-5
															input(type='checkbox', name='unlisted_local', value='true' checked=board.settings.unlistedLocal)
													.row
														.label #{__('Unlist from webring')}
														label.postform-style.ph-5
															input(type='checkbox', name='unlisted_webring', value='true' checked=board.settings.unlistedWebring)

											.tab.tab-2
												.col
													.row
														.label #{__('Anon Name')}
														input(type='text' name='default_name' value=board.settings.defaultName)
													.row
														.label #{__('User Post Deletion')}
														label.postform-style.ph-5
															input(type='checkbox', name='user_post_delete', value='true' checked=board.settings.userPostDelete)
													.row
														.label #{__('Force Anon')}
														label.postform-style.ph-5
															input(type='checkbox', name='force_anon', value='true' checked=board.settings.forceAnon)
													.row
														.label #{__('Sage Only Email')}
														label.postform-style.ph-5
															input(type='checkbox', name='sage_only_email', value='true' checked=board.settings.sageOnlyEmail)
													.row
														.label #{__('Force Thread Subject')}
														label.postform-style.ph-5
															input(type='checkbox', name='force_thread_subject', value='true' checked=board.settings.forceThreadSubject)
													.row
														.label #{__('Force Thread Message')}
														label.postform-style.ph-5
															input(type='checkbox', name='force_thread_message', value='true' checked=board.settings.forceThreadMessage)
													.row
														.label #{__('Force Thread File')}
														label.postform-style.ph-5
															input(type='checkbox', name='force_thread_file', value='true' checked=board.settings.forceThreadFile)
													.row
														.label #{__('Force Reply Message')}
														label.postform-style.ph-5
															input(type='checkbox', name='force_reply_message', value='true' checked=board.settings.forceReplyMessage)
													.row
														.label #{__('Force Reply File')}
														label.postform-style.ph-5
															input(type='checkbox', name='force_reply_file', value='true' checked=board.settings.forceReplyFile)
													.row
														.label #{__('Disable Reply Subject')}
														label.postform-style.ph-5
															input(type='checkbox', name='disable_reply_subject', value='true' checked=board.settings.disableReplySubject)
													.row
														.label #{__('Min Thread Message Length')}
														input(type='number' name='min_thread_message_length' value=board.settings.minThreadMessageLength min=0 max=globalLimits.fieldLength.message)
													.row
														.label #{__('Min Reply Message Length')}
														input(type='number' name='min_reply_message_length' value=board.settings.minReplyMessageLength min=0 max=globalLimits.fieldLength.message)
													.row
														.label #{__('Max Thread Message Length')}
														input(type='number' name='max_thread_message_length' value=board.settings.maxThreadMessageLength min=0 max=globalLimits.fieldLength.message)
													.row
														.label #{__('Max Reply Message Length')}
														input(type='number' name='max_reply_message_length' value=board.settings.maxReplyMessageLength min=0 max=globalLimits.fieldLength.message)

											.tab.tab-3
												.col
													.row
														.label #{__('Max Files')}
														input(type='number' name='max_files' value=board.settings.maxFiles max=globalLimits.postFiles.max)
													.row
														.label #{__('Allow Video Files')}
														label.postform-style.ph-5
															input(type='checkbox', name='files_allow_video', value='true' checked=board.settings.allowedFileTypes.video)
													.row
														.label #{__('Allow Image Files')}
														label.postform-style.ph-5
															input(type='checkbox', name='files_allow_image', value='true' checked=board.settings.allowedFileTypes.image)
													.row
														.label #{__('Allow Animated Image Files')}
														label.postform-style.ph-5
															input(type='checkbox', name='files_allow_animated_image', value='true' checked=board.settings.allowedFileTypes.animatedImage)
													.row
														.label #{__('Allow Audio Files')}
														label.postform-style.ph-5
															input(type='checkbox', name='files_allow_audio', value='true' checked=board.settings.allowedFileTypes.audio)
													.row
														.label #{__('Allow Other Files')}
														label.postform-style.ph-5
															input(type='checkbox', name='files_allow_other', value='true' checked=board.settings.allowedFileTypes.other)
													.row
														.label #{__('User File Spoilering')}
														label.postform-style.ph-5
															input(type='checkbox', name='user_post_spoiler', value='true' checked=board.settings.userPostSpoiler)
													.row
														.label #{__('User File Unlinking')}
														label.postform-style.ph-5
															input(type='checkbox', name='user_post_unlink', value='true' checked=board.settings.userPostUnlink)

											.tab.tab-4
												.col
													.row
														.label #{__('Thread Limit')}
														input(type='number' name='thread_limit' value=board.settings.threadLimit min=globalLimits.threadLimit.min max=globalLimits.threadLimit.max)
													.row
														.label #{__('Reply Limit')}
														input(type='number' name='reply_limit' value=board.settings.replyLimit min=globalLimits.replyLimit.min max=globalLimits.replyLimit.max)
													.row
														.label #{__('Bump Limit')}
														input(type='number' name='bump_limit' value=board.settings.bumpLimit min=globalLimits.bumpLimit.min max=globalLimits.bumpLimit.max)
													.row
														.label #{__('Enforce Unique Files')}
														select(name='file_r9k_mode')
															option(value='0', selected=board.settings.fileR9KMode === 0) #{__('Off')}
															option(value='1', selected=board.settings.fileR9KMode === 1) #{__('Per Thread')}
															option(value='2', selected=board.settings.fileR9KMode === 2) #{__('Board Wide')}
													.row
														.label #{__('Enforce Unique Messages')}
														select(name='message_r9k_mode')
															option(value='0', selected=board.settings.messageR9KMode === 0) #{__('Off')}
															option(value='1', selected=board.settings.messageR9KMode === 1) #{__('Per Thread')}
															option(value='2', selected=board.settings.messageR9KMode === 2) #{__('Board Wide')}
													.row
														.label #{__('OP Reply Count Delete Protection')}
														input(type='number' name='delete_protection_count' value=board.settings.deleteProtectionCount)
													.row
														.label #{__('OP Thread Age Delete Protection')}
														input(type='text' name='delete_protection_age' placeholder=__('e.g. 1w') value=board.settings.deleteProtectionAge)

											.tab.tab-5
												.col
													.row
														a.label(href='/faq.html#antispam') #{__('Antispam FAQ')}
													.row
														.label #{__('Lock Mode')}
														select(name='lock_mode')
															option(value='0', selected=board.settings.lockMode === 0) #{__('Unlocked')}
															option(value='1', selected=board.settings.lockMode === 1) #{__('Lock thread creation')}
															option(value='2', selected=board.settings.lockMode === 2) #{__('Lock board')}
													.row
														.label #{__('Captcha Mode')}
														select(name='captcha_mode')
															option(value='0', selected=board.settings.captchaMode === 0) #{__('No Captcha')}
															option(value='1', selected=board.settings.captchaMode === 1) #{__('Captcha for new thread')}
															option(value='2', selected=board.settings.captchaMode === 2) #{__('Captcha for all posts')}
													.row
														.label #{__('PPH Trigger Threshold')}
														input(type='number', name='pph_trigger', value=board.settings.pphTrigger)
													.row
														.label #{__('PPH Trigger Action')}
														select(name='pph_trigger_action')
															option(value='0', selected=board.settings.pphTriggerAction === 0) #{__('Do nothing')}
															option(value='1', selected=board.settings.pphTriggerAction === 1) #{__('Enable captcha for new thread')}
															option(value='2', selected=board.settings.pphTriggerAction === 2) #{__('Enable captcha for all posts')}
															option(value='3', selected=board.settings.pphTriggerAction === 3) #{__('Lock thread creation')}
															option(value='4', selected=board.settings.pphTriggerAction === 4) #{__('Lock board')}
													.row
														.label #{__('TPH Trigger Threshold')}
														input(type='number', name='tph_trigger', value=board.settings.tphTrigger)
													.row
														.label #{__('TPH Trigger Action')}
														select(name='tph_trigger_action')
															option(value='0', selected=board.settings.tphTriggerAction === 0) #{__('Do nothing')}
															option(value='1', selected=board.settings.tphTriggerAction === 1) #{__('Enable captcha for new thread')}
															option(value='2', selected=board.settings.tphTriggerAction === 2) #{__('Enable captcha for all posts')}
															option(value='3', selected=board.settings.tphTriggerAction === 3) #{__('Lock thread creation')}
															option(value='4', selected=board.settings.tphTriggerAction === 4) #{__('Lock board')}
													.row
														.label #{__('Trigger Reset Lock Mode')}
														select(name='lock_reset')
															option(value='0', selected=board.settings.lockReset === 0) #{__('No change')}
															option(value='1', selected=board.settings.lockReset === 1) #{__('Unlock board')}
															option(value='2', selected=board.settings.lockReset === 2) #{__('Lock thread creation')}
													.row
														.label #{__('Trigger Reset Captcha Mode')}
														select(name='captcha_reset')
															option(value='0', selected=board.settings.captchaReset === 0) #{__('No change')}
															option(value='1', selected=board.settings.captchaReset === 1) #{__('Captcha disabled')}
															option(value='2', selected=board.settings.captchaReset === 2) #{__('Captcha for new thread')}
													.row
														.label #{__('Early 404')}
														label.postform-style.ph-5
															input(type='checkbox', name='early404', value='true' checked=board.settings.early404)
													.row
														.label #{__('Disable anonymizer file posting')}
														label.postform-style.ph-5
															input(type='checkbox', name='disable_anonymizer_file_posting', value='true' checked=board.settings.disableAnonymizerFilePosting)
													.row
														.label #{__('Blocked Countries')}
														include ../includes/2charisocountries.pug

			include ../includes/forceactiontwofactor.pug
			input.row(type='submit', value=__('Save settings'))


code:
extends ../layout.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Staff')}

block content
	+boardheader(__('Staff'))
	br
	+managenav('staff')
	hr(size=1)
	.form-wrapper.flexleft
		h4.no-m-p #{__('Add Staff')}:
		form.form-post.mv-5(action=`/forms/board/${board._id}/addstaff` method='POST' enctype='application/x-www-form-urlencoded')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__('Username')}
				input(type='text' name='username' required)
			input(type='submit', value=__('Add'))
	hr(size=1)
	h4.no-m-p #{__('Current Staff')}:
	//-ew
	- const staffEntries = Object.entries(board.staff).sort((a, b) => new Date(a[1].addedDate) - new Date(b[1].addedDate));
	if staffEntries.length > 0
		form.form-post.nogrow(action=`/forms/board/${board._id}/deletestaff` method='POST' enctype='application/x-www-form-urlencoded')
			input(type='hidden' name='_csrf' value=csrf)
			.table-container.flex-left.mv-5.text-center
				table
					tr
						th
						th #{__('Username')}
						th #{__('Date Added')}
						th #{__('Logs')}
						th #{__('Permissions')}
					for staff in staffEntries
						tr
							td: input(type='checkbox' name='checkedstaff' value=staff[0])
							td #{staff[0]}#{user.username === staff[0] ? ' '+__('(You)') : ''}
							td
								time.reltime(datetime=staff[1].addedDate) #{staff[1].addedDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
							td: a(href=`/${board._id}/manage/logs.html?username=${staff[0]}`) [#{__('View')}]
							td
								if user.username !== staff[0]
									a(href=`/${board._id}/manage/editstaff/${staff[0]}.html`) [#{__('Edit')}]
								else
									a(href=`/${board._id}/manage/mypermissions.html`) [#{__('View')}]

			h4.no-m-p #{__('Delete Selected')}:
			input(type='submit', value='Delete')

	else
		p #{__('None')}


code:
extends ../layout.pug

block head
	title #{title}
	if redirect
		meta(http-equiv="refresh" content=`3;url=${redirect}`)

block content
	h1 #{title}
	ul
		if message
			li #{message}
		if error
			li #{error}
		if messages
			each msg in messages
				li #{msg}
		if errors
			each error in errors
				li #{error}
	if link
		div
			a.button(href=link.href target='_blank') #{link.text}
	if redirect
		p #{__('You will be redirected shortly.')} #[a(href=redirect) #{__('Click here if you are not redirected automatically.')}]


code:
extends ../layout.pug
include ../mixins/boardheader.pug
include ../mixins/boardnav.pug
include ../mixins/postlink.pug

block head
	title /#{board._id}/ - #{__('Logs for %s', startDate.toDateString())}

block content
	+boardheader(__('Logs'))
	br
	include ../includes/stickynav.pug
	.pages
		+boardnav('logs', true, true)
	hr(size=1)
	.table-container.flex-center.mv-10.text-center
		table
				tr
					th #{__('Date')}
					th #{__('User')}
					th #{__('Actions')}
					th #{__('Links')}
					th #{__('Log Message')}
				for log in logs
					tr
						- const logDate = new Date(log.date);
						td: time.reltime(datetime=logDate.toISOString()) #{logDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
						- const logUser = log.user || __('Unregistered User');
						td(class=(!log.showUser ? 'em' : '')) #{log.showUser ? logUser : __('Hidden User')}
						td #{log.actions.map(a => __(a))}
						td
							if log.showLinks
								for postLink in log.postLinks
									+postlink(log, postLink, false)
									|
							else
								| #{log.postLinks.map(l => l.postId)}
						td #{log.message || '-'}
	hr(size=1)
	.pages
		+boardnav('logs', true, true)


code:
extends ../layout.pug
include ../mixins/boardheader.pug
include ../mixins/boardnav.pug

block head
	title /#{board._id}/ - #{__('Logs')}

block content
	+boardheader(__('Logs'))
	br
	include ../includes/stickynav.pug
	.pages
		+boardnav('logs', true, false)
	hr(size=1)
	if dates.length === 0
		p #{__('No Logs.')}
	else
		.table-container.flex-center.mv-10.text-center
			table
				tr
					th #{__('Date')}
					th #{__('Events')}
				for row in dates
					tr
						-
							const { date, count } = row;
							const day = ('0'+date.day).slice(-2);
							const month = ('0'+date.month).slice(-2);
							const year = date.year;
							const logName = `${month}-${day}-${year}`;
						td: a(href=`logs/${logName}.html`) #{logName}
						td #{count}
	hr(size=1)
	.pages
		+boardnav('logs', true, false)


code:
extends ../layout.pug
include ../mixins/mypermissions.pug

block head
	title #{__('My Permisions')}

block content
	.board-header
		h1.board-title #{__('My Permissions')}
	br
	hr(size=1)
	h4.no-m-p #{__('Board-specific permissions')}
	if user.ownedBoards && user.ownedBoards.length > 0 || user.staffBoards && user.staffBoards.length > 0
		ul
			for b in user.ownedBoards
				li
					a(href=`/${b}/manage/mypermissions.html`) /#{b}/
			for b in user.staffBoards
				li
					a(href=`/${b}/manage/mypermissions.html`) /#{b}/
	else
		p #{__('None')}
	hr(size=1)
	h4.mv-5 #{__('Account permissions')}
		|
		if permissions.get(Permissions.MANAGE_GLOBAL_ACCOUNTS)
			|
			a(href=`/globalmanage/editaccount/${user.username}.html`) [#{__('Edit')}]
	- const jsonPermissions = permissions.toJSON();
	+mypermissions(jsonPermissions)


code:
extends ../layout.pug
include ../mixins/newspost.pug

block head
	title #{__('News')}

block content
	h1.board-title #{__('News')}
	if news.length === 0
		p.text-center #{__('No news.')}
	else
		include ../includes/stickynav.pug
		each post in news
			+newspost(post)


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/overboardform.pug
include ../mixins/announcements.pug

block head
	title #{__('Overboard Index')}

block content
	.board-header
		h1.board-title #{__('Overboard Index')}
		h4.board-description #{__('Recently bumped threads from multiple boards')}
			|
			| (
			a(href=`/catalog.html?${cacheQueryString}`) #{__('Catalog View')}
			| )
	include ../includes/stickynav.pug
	if allowCustomOverboard === true
		+overboardform('/overboard.html')
	+announcements(true, true, false)
	hr(size=1)
	if threads.length === 0
		p #{__('No posts.')}
	for thread in threads
		h4.no-m-p #{__('Thread from')} #[a(href=`/${thread.board}/index.html`) /#{thread.board}/]
		.thread
			+post(thread, true, false, false, false, true)
			for post in thread.replies
				+post(post, true, false, false, false, true)
		hr(size=1)


code:
extends ../layout.pug
include ../mixins/catalogtile.pug
include ../mixins/overboardform.pug
include ../mixins/announcements.pug

block head
	title #{__('Overboard Catalog')}

block content
	.board-header.mb-5
		h1.board-title #{__('Overboard Catalog')}
		h4.board-description #{__('Recently bumped threads from multiple boards')}
			|
			| (
			a(href=`/overboard.html?${cacheQueryString}`) #{__('Index View')}
			| )
	if allowCustomOverboard === true
		+overboardform('/catalog.html')
	+announcements()
	include ../includes/stickynav.pug
	.wrapbar
		.pages.jsonly
			input#catalogfilter(type='text' placeholder=__('Filter'))
			select.ml-5.right#catalogsort
				option(value="" disabled selected hidden) #{__('Sort By')}
				option(value="bump") #{__('Bump Order')}
				option(value="date") #{__('Creation Date')}
				option(value="replies") #{__('Reply Count')}
	hr(size=1)
	if threads.length === 0
		p #{__('No posts.')}
	else
		.catalog
			for thread, i in threads
				+catalogtile(thread, i, true)
	hr(size=1)


code:
extends ../layout.pug

block head
	title #{__('Register')}

block content
	h1.board-title #{__('Register')}

	.mv-10
		if enableWeb3 === true
			.sm#tab-1
				.sm#tab-2
					.tabbed-area.flexcenter
						ul.tabs.group.web3
							li
								a(href='#tab-1') #{__('Username')}
							li.jsonly
								a(href='#tab-2') #{__('MetaMask')}
						.box-wrap.mv-0.wm
							.tab.tab-1
								.form-wrapper.flex-center
									include ../includes/registration.pug
							.tab.tab-2.jsonly.web3
								.form-wrapper.flex-center
									form.form-post(action='/forms/register' method='POST' data-captcha-preload='true')
										input(type='hidden' name='nonce')
										input(type='hidden' name='address')
										input(type='hidden' name='signature')
										if captchaOptions.type === 'text'
											include ../includes/captchasidelabel.pug
										else
											include ../includes/captchafieldrow.pug
										.postform-style.dummy-link.web3-login.ct-r1.ph-5
											img(src='/file/metamask-fox.svg' width=24 height=24)
											| #{__('Register with MetaMask')}
		else
			.form-wrapper.flex-center.mv-10
				include ../includes/registration.pug
	.text-center.mt-10
		p: a(href='/login.html') #{__('Login')}
		p: a(href='/changepassword.html') #{__('Change Password')}


code:
extends ../layout.pug

block head
	title #{__('Sessions')}

block content
	.board-header
		h1.board-title #{__('Active Sessions')}
	br
	hr(size=1)
	h4.mv-5 #{__('Active Sessions')}:
	form.form-post.nogrow(action=`/forms/deletesessions` method='POST' enctype='application/x-www-form-urlencoded')
		input(type='hidden' name='_csrf' value=csrf)
		.table-container.flex-left.text-center
			table
				tr
					th
					th #{__('ID')}
					th #{__('Expires')}
				each session, sessionId in sessions
					tr(class=(sessionId === currentSessionKey ? 'bold' : ''))
						td: input(type='checkbox', name='checkedsessionids' value=sessionId)
						td #{sessionId} #{sessionId === currentSessionKey ? '(current)' : ''}
						- const expiryDate = new Date(session.cookie.expires)
						td: time.reltime(datetime=expiryDate.toISOString()) #{expiryDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
		h4.mv-5 #{__('Delete Selected')}:
		input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/boardnav.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/announcements.pug

block head
	- const subjectString = thread.subject || (thread.nomarkup ? `${thread.nomarkup.substring(0, globalLimits.fieldLength.subject)}${thread.nomarkup.length > globalLimits.fieldLength.subject ? '...' : ''}` : thread.postId);
	title /#{board._id}/ - #{subjectString}
	if !modview
		meta(property='og:title', content=thread.subject)
		meta(property='og:description', content=thread.nomarkup)
		if thread.files.length > 0
			if thread.spoiler || thread.files[0].spoiler
				meta(property='og:image', content='/file/spoiler.png')
			else
				- const file = thread.files[0];
				- const maintype = file.mimetype.split('/')[0];
				case maintype
					when 'image'
					when 'video'
					when 'audio'
						meta(property=`og:${maintype}`, content=`/file/${file.filename}`)
						- break
					default
						- break

block content
	+boardheader(modview ? __('Mod View') : null)
	br
	if thread.replyposts >= board.settings.replyLimit && !thread.cyclic && !modview
		p.title.text-center #{__('⊖ Thread has reached reply limit.')}
	else
		include ../includes/postform.pug
		br
	+announcements()
	include ../includes/stickynav.pug
	if modview
		+managenav(null, true)
	else
		.pages
			+boardnav(null, true, true)
	- const uids = board.settings.ids ? new Set() : void 0;
	form(action=`/forms/board/${board._id}/${modview ? 'mod' : ''}actions` method='POST' enctype='application/x-www-form-urlencoded')
		if modview
			input(type='hidden' name='_csrf' value=csrf)
		hr(size=1)
		.thread
			- uids && thread.userId && uids.add(thread.userId)
			+post(thread)
			for post in thread.replies
				- uids && post.userId && uids.add(post.userId)
				+post(post)
		if thread.replyposts >= board.settings.replyLimit && !thread.cyclic && !modview
			p.title.text-center #{__('⊖ Thread has reached reply limit.')}
		else
			a.bottom-reply.no-decoration.post-button(href='#postform') [#{__('New Reply')}]
		hr(size=1)
		.wrapbar
			if modview
				+managenav(null, true)
			else
				.pages
					+boardnav(null, true, true)
			#threadstats
				span #{__n('%s replies', thread.replyposts)}
				|  |
				span #{__n('%s files', thread.replyfiles + thread.files.length)}
				if board.settings.ids
					|  |
					span #{__n('%s UIDs', uids.size)}
		.jsonly#livetext
			.dot#livecolor
			|  #{__('Connecting...')}
			input.postform-style.ml-5.di#updatepostsbutton(type='button' value=__('Update'))
		if modview
			include ../includes/actionfooter_manage.pug
		else
			include ../includes/actionfooter.pug


code:
extends ../layout.pug

block head
	title #{__('Two Factor Authentication Setup')}

block content
	.board-header
		h1.board-title #{__('Two Factor Authentication Setup')}
	.form-wrapper.flex-center.mv-10
		form.form-post.nogrow(action=`/forms/twofactor` method='POST' enctype='application/x-www-form-urlencoded')
			input(type='hidden' name='_csrf' value=csrf)

			h4.mv-5 #{__('Scan the QR Code in an authenticator app, and submit the code')}:
			.row
				span.code.hljs.twofactor.noselect #{qrCodeText}
			.row
				h4.no-m-p #{__('No camera? Use this secret in your authenticator app instead')}:
			.row
				span.code #{secretBase32}
			.row
				h4.mv-5.ban #{__('Enabling 2FA will invalidate all your existing sessions and you will have to login again.')}
			.row
				.label #{__('2FA Code')}
				input(type='number' name='twofactor' placeholder=__('6 digits'))
			.row
				input(type='submit', value=__('Submit'))


code:
'use strict';

process
	.on('uncaughtException', console.error)
	.on('unhandledRejection', console.error);

const Mongo = require(__dirname+'/db/db.js')
	, config = require(__dirname+'/lib/misc/config.js');

(async () => {

	await Mongo.connect();
	await Mongo.checkVersion();
	await config.load();

	const tasks = require(__dirname+'/lib/build/tasks.js')
		, { queue } = require(__dirname+'/lib/build/queue.js');

	queue
		.on('error', console.error)
		.on('failed', console.warn);

	queue.process(async job => {
		await tasks[job.data.task](job.data.options);
		return null;
	});

})();


code:
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs     diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln       merge=binary
#*.csproj    merge=binary
#*.vbproj    merge=binary
#*.vcxproj   merge=binary
#*.vcproj    merge=binary
#*.dbproj    merge=binary
#*.fsproj    merge=binary
#*.lsproj    merge=binary
#*.wixproj   merge=binary
#*.modelproj merge=binary
#*.sqlproj   merge=binary
#*.wwaproj   merge=binary

###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg   binary
#*.png   binary
#*.gif   binary

###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc   diff=astextplain
#*.DOC   diff=astextplain
#*.docx  diff=astextplain
#*.DOCX  diff=astextplain
#*.dot   diff=astextplain
#*.DOT   diff=astextplain
#*.pdf   diff=astextplain
#*.PDF   diff=astextplain
#*.rtf   diff=astextplain
#*.RTF   diff=astextplain

path: .gitattributes

license: unknown


code:
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb
/Source/Patches/PawnAnimationPatches/HarmonyPatch_Pawn_DrawTracker.cs
/Source/Patches/PawnAnimationPatches/HarmonyPatch_PawnRotation.cs
/Source/Patches/PawnAnimationPatches/HarmonyPatch_PawnRenderer.cs
/Source/Patches/OtherModPatches/HarmonyPatch_ShowHairWithHats.cs
/Source/Patches/OtherModPatches/HarmonyPatch_FacialAnimation.cs
/Source/Patches/OtherModPatches/HarmonyPatch_DontShaveYourHead.cs
/Source/Patches/OtherModPatches/HarmonyPatch_CSL.cs
/Source/Patches/OtherModPatches/HarmonyPatch_AlienRace.cs
/Source/Patches/ThingAnimationPatches/HarmonyPatch_ThingDrawAt.cs
/Defs/AnimationDefs/Animations_SexToys.xml

path: .gitignore