initial commit

This commit is contained in:
Luke Ogburn
2019-03-30 22:43:34 -04:00
commit c4a666e3b6
78 changed files with 5332 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
conn.php
googleApi/

0
.htaccess Normal file
View File

27
404.shtml Normal file
View File

@@ -0,0 +1,27 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
?>
<!DOCTYPE html>
<html>
<head>
<meta charset=UTF-8>
<title>IB Forum</title>
<link rel=stylesheet type=text/css href=/style.css>
<link rel=stylesheet type=text/css href=/mobile.css>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="icon" href="/res/i/favicon.png">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<?php include "res/top"; ?>
<div id=container>
<div>
<h1>Can't find that page.</h1>
<p>I had one job. And I failed.</p>
</div>
</div>
</body>
</html>

39
admin/index.php Normal file
View File

@@ -0,0 +1,39 @@
<?php require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php"; ?>
<!--
Hello there! Thanks for checking out this website!
It's still very much in development, but I've made steady progress so far and I'm hopeful that it'll actually be used this school year.
I do need some help! If you want to give me suggestions for features or design improvements, shoot me a text: 804-912-5784
-->
<!DOCTYPE html>
<html>
<?php include "../res/head"; ?>
<body>
<?php
include "../res/top";
?>
<div id=monoContainer>
<div class="card noHover center">
<h2>ADMIN ACCOUNTS</h2>
<p><?php
conn();
$stmt = $conn->prepare("SELECT * FROM users WHERE special='owner'");
$stmt->execute();
$row = $stmt->fetchAll();
foreach($row as $person){
echo "<a class=noStyle href=/user/?user=".$person["id"].">".$person["name"]."</a><br>";
}
$stmt = $conn->prepare("SELECT * FROM users WHERE special='admin'");
$stmt->execute();
$row = $stmt->fetchAll();
foreach($row as $person){
echo "<a class=noStyle href=/user/?user=".$person["id"].">".$person["name"]."</a><br>";
}
?></p>
</div>
<div class="card noHover center">
<h2>WANT TO BE AN ADMIN?</h2>
<p>Contact Luke Ogburn (@<?=getUserInfo("51155")->name?>) to get more information.</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,75 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
restrictAccess("owner");
$user = getUserInfo($_GET["user"]);
if($user == false){
msg("That user doesn't exist.");
header("Location: /forum");
}
//Getting the number of posts
$stmt = $conn->prepare("SELECT * FROM forums WHERE poster_id = :usr");
$stmt->bindparam(":usr", $user->id);
$stmt->execute();
$posts = $stmt->rowCount();
//Getting the number of comments
$stmt = $conn->prepare("SELECT * FROM comments WHERE poster_id = :usr");
$stmt->bindparam(":usr", $user->id);
$stmt->execute();
$comments = $stmt->rowCount();
//Getting the number of reported posts made by user
$stmt = $conn->prepare("SELECT * FROM forums WHERE poster_id = :usr AND reports IS NOT NULL");
$stmt->bindparam(":usr", $user->id);
$stmt->execute();
$reportedPosts = $stmt->rowCount();
//Getting the number of reported comments made by user
$stmt = $conn->prepare("SELECT * FROM comments WHERE poster_id = :usr AND reports IS NOT NULL");
$stmt->bindparam(":usr", $user->id);
$stmt->execute();
$reportedComments = $stmt->rowCount();
?>
<!DOCTYPE html>
<html>
<?php
$css = "/admin/portal/admin";
include "../../res/head";
?>
<body>
<?php
include "../../res/top";
?>
<div id=monoContainer>
<div class="card noHover center">
<h2><?=$user->name?></h2>
<?php
$name = $user->name;
$id = $user->id;
$login = makeDate($user->last_login);
if($posts == 0){
$reportedPostsPercent = 0;
}else{
$reportedPostsPercent = round($reportedPosts/$posts);
}
if($comments == 0){
$reportedCommentsPercent = 0;
}else{
$reportedCommentsPercent = round($reportedComments/$comments);
}
echo "
<p>Last login: $login</p>
<p>Posts made: $posts</p>
<p>Reported posts made: $reportedPosts</p>
<p>Percent of posts reported: $reportedPostsPercent%</p>
<p>Comments made: $comments</p>
<p>Reported comments made: $reportedComments</p>
<p>Percent of comments reported: $reportedCommentsPercent%</p>
<p><a class=noStyle href=/user/?user=$id>User's page</a></p>
";
?>
</div>
</body>
</html>

5
admin/portal/admin.css Normal file
View File

@@ -0,0 +1,5 @@
#userBanMsg{
font-style: italic;
width: 70%;
margin: 1.5em auto;
}

57
admin/portal/banUser.php Normal file
View File

@@ -0,0 +1,57 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
restrictAccess("admin");
//Banning user
if(isset($_POST["person"]) && strval(getUserInfo($_POST["person"])->name) != ""){
if(verifyUser("admin", $_POST["person"])){
msg("You cannot ban that user");
unset($_POST);
header("Location: /admin/portal/banUser.php");
exit();//needed for some reason, else the code below runs
}
$person = $_POST["person"];
$reason = $_POST["reason"];
unset($_POST);
conn();
$stmt = $conn->prepare("UPDATE users SET special='banned', ban_reason=:rsn WHERE id=:id");
$stmt->bindParam(":rsn", $reason);
$stmt->bindParam(":id", $person);
$stmt->execute();
if($stmt){
$user = getUserInfo($person)->name;
msg("$user has been banned");
header("Location: /admin/portal/banUser.php");
}
}else if(isset($_POST["person"]) && strval(getUserInfo($_POST["person"])->name) == ""){
unset($_POST);
msg("User doesn't exist");
header("Location: /admin/portal/banUser.php");
}
?>
<!DOCTYPE html>
<html>
<?php
$css = "/admin/portal/admin";
include "../../res/head";
?>
<body>
<?php
include "../../res/top";
?>
<div id=monoContainer>
<div class="card noHover center">
<h2>BAN USER</h2>
<p id=userBanMsg>Banning a user will make them unable to access the website. Only do this if there is good reason to do so (e.g. cheating or bullying). This can only be undone by Luke Ogburn.</p>
<form action="" method=POST>
<p>User's ID (NOT their username):</p>
<input type=text name=person placeholder="User's ID" required><br>
<p>Reason for banning user (for them to read):</p>
<input type=text name=reason placeholder="Reason for ban" required>
<button type=submit>Ban User</button>
</form>
<br>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,51 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
restrictAccess("owner");
$classes = file_get_contents($_SERVER['DOCUMENT_ROOT']."/res/classes");
$classes = array_filter(explode(",", $classes));
if(isset($_GET["del"]) && in_array($_GET["del"], $classes)){
$classes = array_diff($classes, array($_GET["del"]));
file_put_contents($_SERVER['DOCUMENT_ROOT']."/res/classes", implode(",", $classes));
msg("Class removed.");
header("Location: editClasses.php");
exit();
}
if(isset($_GET["add"]) && !in_array($_GET["add"], $classes)){
$class = str_replace(" ", "_", $_GET["add"]);
$class = strtolower($class);
array_push($classes, $class);
file_put_contents($_SERVER['DOCUMENT_ROOT']."/res/classes", implode(",", $classes));
msg("Class added.");
header("Location: editClasses.php");
exit();
}
?>
<!DOCTYPE html>
<html>
<?php
$css = "/admin/portal/admin";
include "../../res/head";
?>
<body>
<?php
include "../../res/top";
?>
<div id=monoContainer>
<div class="card noHover center">
<h2>DELETE A CLASS:</h2>
<?php
foreach($classes as $class){
echo "<p><a class=deletable href=?del=$class>".ucwords(str_replace('_', ' ', $class))."</a></p>";
}
?>
</div>
<div class='card noHover center'>
<h2>ADD A CLASS:</h2>
<form>
<input type=text name=add>
<button type=submit>Add Class</button>
</form>
</div>
</body>
</html>

View File

@@ -0,0 +1,45 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
restrictAccess("owner");
conn();
?>
<!DOCTYPE html>
<html>
<?php
include $_SERVER['DOCUMENT_ROOT']."/res/head";
?>
<body>
<?php
if(isset($_GET["del"])){
conn();
$del = $conn->prepare("DELETE FROM issue_tracker WHERE id = :id");
$del->bindParam(":id", $_GET["del"]);
$del->execute();
if($del){
msg("Good job :)");
header("Location: /admin/portal/errorReports.php");
}
}
include $_SERVER['DOCUMENT_ROOT']."/res/top";
$stmt = $conn->prepare("SELECT * FROM issue_tracker ORDER BY date DESC");
$stmt->execute();
$stmt = $stmt->fetchAll();
?>
<div id=monoContainer>
<div class="card noHover center">
<h2>REPORTED ISSUES</h2>
<?php
foreach($stmt as $report){
echo "<a class=deletable href='?del=".$report["id"]."'>".$report['comment']."</a><br>";
echo "<small>Reported by: ".$report["reporter"]." (".getUserInfo($report["reporter"])->name.") ".makeDate($report["date"])."</small><br><br>";
}
if($stmt == NULL){
echo "<i>No issues have been reported :D</i><br>";
}
?>
<br>
</div>
</div>
</body>

48
admin/portal/index.php Normal file
View File

@@ -0,0 +1,48 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
restrictAccess("admin");
?>
<!DOCTYPE html>
<html>
<?php
$css = "/admin/portal/admin";
include "../../res/head";
?>
<body>
<?php
include "../../res/top";
?>
<div id=monoContainer>
<div class="card noHover center">
<h2>NOTIFICATIONS</h2>
<?php
conn();
$stmt = $conn->prepare("SELECT * FROM forums WHERE reports IS NOT NULL");
$stmt->execute();
$res = $stmt->fetchAll();
foreach($res as $post){
$times = substr_count($post["reports"], ",");
$times = $times==1?"1 time":"$times times";
echo "<p><a class=noStyle href=reportedPost.php?post=".$post['post_id'].">Post ".$post["post_id"]." has been reported $times</a></p>";
}
if(count($res)==0){
echo "<p><i>Nothing has been reported.</i></p>";
}
?>
</div>
<div class="card noHover center">
<h2>ADMIN ACTIONS</h2>
<p><a class=noStyle href=banUser.php>Ban a user</a></p>
<p><a class=noStyle href=unbanUser.php>Unban a user</a></p>
<?php
if(verifyUser("owner")){
echo "<p><a class=noStyle href=errorReports.php>Error reports</a></p>";
echo "<p><a class=noStyle href=manage.php>Manage admins</a></p>";
echo "<p><a class=noStyle href=siteVisitors.php>Site visitors</a></p>";
echo "<p><a class=noStyle href=editClasses.php>Edit classes</a></p>";
}
?>
</div>
</div>
</body>
</html>

88
admin/portal/manage.php Normal file
View File

@@ -0,0 +1,88 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
restrictAccess("owner");
//Adding admins
if(isset($_POST["person"]) && strval(getUserInfo($_POST["person"])->name) != ""){
$person = $_POST["person"];
unset($_POST);
conn();
$stmt = $conn->prepare("UPDATE users SET special='admin' WHERE id=:id");
$stmt->bindParam(":id", $person);
$stmt->execute();
if($stmt){
$user = getUserInfo($person)->name;
msg("$user added as admin");
header("Location: /admin/portal/manage.php");
}
}else if(isset($_POST["person"]) && strval(getUserInfo($_POST["person"])->name) == ""){
unset($_POST);
msg("User doesn't exist");
header("Location: /admin/portal/manage.php");
}
//Deleting admins
if(isset($_GET["delUser"])){
conn();
$person = $_GET["delUser"];
$stmt = $conn->prepare("SELECT special FROM users WHERE id=:id");
$stmt->bindParam(":id", $person);
$stmt->execute();
$res = $stmt->fetch(PDO::FETCH_ASSOC);
if($res["special"]=="admin"){
$person = $_GET["delUser"];
$stmt = $conn->prepare("UPDATE users SET special=null WHERE id=:id");
$stmt->bindParam(":id", $person);
$stmt->execute();
if($stmt){
$person = getUserInfo($person)->name;
msg("$person's admin rights have been revoked");
header("Location: /admin/portal/manage.php");
}else{
msg("Error revoking $person's admin rights");
reportError("Error revoking admin rights from $person in /admin/portal/manage.php");
header("Location: /admin/portal/manage.php");
}
}else{
msg("That person is not an admin");
header("Location: /admin/portal/manage.php");
}
}
?>
<!DOCTYPE html>
<html>
<?php
$css = "/admin/portal/admin";
include "../../res/head";
?>
<body>
<?php
include "../../res/top";
?>
<div id=monoContainer>
<div class="card noHover center">
<h2>ADD ADMIN</h2>
<form action="manage.php" method=POST>
<input type=text name=person placeholder="User's ID">
<button type=submit>Add admin</button>
</form>
<br>
</div>
<div class="card noHover center">
<h2>REMOVE ADMIN</h2>
<p><?php
conn();
$stmt = $conn->prepare("SELECT * FROM users WHERE special='admin'");
$stmt->execute();
$row = $stmt->fetchAll();
if(sizeof($row)==0){
echo "<i>No admins.</i>";
}
foreach($row as $person){
echo "<a class=deletable href=/admin/portal/manage.php?delUser=".$person["id"].">".$person["name"]."</a><br>";
}
?></p>
</div>
</div>
</body>
</html>

126
admin/portal/post.css Normal file
View File

@@ -0,0 +1,126 @@
/* ------------- Global post ------------- */
.container{
width: 60%;
margin: 2% auto 0 auto;
color: #333;
background-color: white;
margin-bottom: 2em;
border-radius: 0.2em;
padding: 1em 2em;
line-height: 1.3em;
}
.container>*{
border-radius: 0.3em;
}
/* General forum stuff */
.forumLink{
text-decoration: none;
}
/* ------------- Post ------------- */
/* Title, username, time posted */
.title>h2{
margin: 0.5em 0;
line-height: 1.2em;
}
.info>*{
font-size: 0.75em;
color: #aaa;
margin: 0;
display: inline-block;
}
.userlink:hover, .postType:hover{
text-decoration: underline;
}
.postType{
color: #888;
font-weight: bold;
margin: 0 0.5em 0 0.2em;
}
/* Text and image */
.content>p{
margin: 0;
}
.forum.card{
margin-bottom: 1em;
}
.postImage{
margin-top: 1em;
width: 100%;
border-radius: 0.3em;
}
.postDocPreview{
margin-top: 1em;
width: 100%;
border-radius: 0.2em;
border: 1px solid #999;
height: 50vh;
}
#show:hover, #hide:hover{
cursor: pointer;
}
#hideImgs{
display: none;
}
#hideImgs ~ #hide{
display: block;
}
#hideImgs ~ #show{
display: none;
}
#hideImgs:checked ~ #hide{
display: none;
}
#hideImgs:checked ~ #show{
display: block;
}
#hideImgs ~ label{
margin-top: 2em;
color: #00d09f;
text-align: center;
font-size: 0.9em;
margin-bottom: 0;
}
#hideImgs:checked ~ .toggleView{
display: none;
}
/* Fixing tag-padding issue
.tags>p{
padding: 0em 0.5em;
}*/
/* Reporting and saving */
.postBottom{
display: block;
height: 1.5em;
font-size: 1em;
padding: 0 1em;
display: grid;
align-content: center;
grid-template-columns: 1fr 1fr;
}
.postReport, .postActions{
margin: 0;
font-size: 0.8em;
color: #999;
}
.postReport{
color: #922;
text-decoration: none;
}
.postActions>a{
color: #888;
text-decoration: none;
}
.postActions>a:hover,.postReport:hover{
text-decoration: underline;
}
.postSave{
color: inherit;
text-decoration: none;
float: right;
}
.postSave>*{
float: right;
}

View File

@@ -0,0 +1,86 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
restrictAccess("admin");
conn();
//Getting and storing the post info to echo later
$post = getPostInfo($_GET["post"]);
$poster_id = $post->poster_id;
$title = $post->title;
$content = decodeUserLink($post->content);
$section = $post->section=="math"?"HL Math":ucwords($post->section);
$section = $post->section=="none"?"":ucwords($post->section);
$type = $post->type=="other"?"":strtolower($post->type);
$type = $section==""?ucwords($type):$type;
$section = $section==$type?"No topic":$section;
$date = $post->date;
$images = $post->image;
$poster = getUserInfo($poster_id)->name;
//Clearing post of reports
if($_GET["clearPost"]){
$stmt = $conn->prepare("UPDATE forums SET reports=null WHERE post_id=:id");
$stmt->bindParam(":id", $_GET["post"]);
$stmt->execute();
if($stmt){
msg("Post cleared of all reports");
header("Location: /forum/post/?post=".$_GET["post"]);
}
}
?>
<!DOCTYPE html>
<html>
<?php
$css2 = 'post';
include "../../res/head";
?>
<body>
<?php
include "../../res/top";
?>
<div class="container center">
<h2>What should happen to the below post?</h2>
<p>Should this post be <a class=color href=/post/delete.php?post=<?=$_GET["post"]?>>deleted</a> or <a class=color href=?clearPost=1&post=<?=$_GET["post"]?>>cleared of reports</a>?</p>
</div>
<div class="container card noHover">
<div id=post>
<div class="forum card noShadow">
<div class=info>
<p onclick="document.location.href = '/search/?q=<?=$section;?>:+'; return false" class=postType><?=$section." ".$type; ?></p>
<p>Posted <?=makeDate($date);?> by <span onclick="document.location.href = '/user/?user=<?=$poster_id;?>'; return false" class=userlink><?=$poster;?></span></p>
</div>
<div class=title>
<h2><?=$title;?></h2>
</div>
<div class=content>
<p>
<?=$content;?>
<?php
if($images != NULL){
echo "<input type=checkbox id=hideImgs>
<label for=hideImgs id=hide class=noSelect>HIDE ATTACHMENTS</label>
<label for=hideImgs id=show class=noSelect>SHOW ATTACHMENTS</label>";
foreach(explode(",", substr($images, 0, -1)) as $file){
//substr gets rid of the last comma, explode makes the array
$exType = substr($file, strpos($file, '.')+1);
$docFiles = ["doc", "docx", "pdf"];
$imgFiles = ["jpg", "jpeg", "png"];
//image stuff
if(in_array($exType, $docFiles)){
echo "<iframe class='postDocPreview toggleView' src=https://docs.google.com/gview?url=http://ib.lukeogburn.com/forum/images/$file&embedded=true></iframe>";
//<embed src="file_name.pdf" width="800px" height="2100px" />
}else if(in_array($exType, $imgFiles)){
echo "<img class='postImage toggleView' src=/forum/images/$file>";
}
}
}
?>
</p>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,32 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
restrictAccess("owner");
?>
<!DOCTYPE html>
<html>
<?php
$css = "/admin/portal/admin";
include "../../res/head";
?>
<body>
<?php
include "../../res/top";
?>
<div id=monoContainer>
<div class="card noHover center">
<h2>USERS:</h2>
<?php
conn();
$stmt = $conn->prepare("SELECT name FROM users WHERE id <> '51155'");
$stmt->execute();
$res = $stmt->fetchAll();
foreach($res as $person){
$person = getUserInfoByName($person[0]);
$name = $person->name;
$id = $person->id;
echo "<p><a class=noStyle href=aboutUser.php?user=$id>$name</a></p>";
}
?>
</div>
</body>
</html>

View File

@@ -0,0 +1,61 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
restrictAccess("admin");
//Unbanning the user
if(isset($_GET["user"])){
conn();
$person = $_GET["user"];
$stmt = $conn->prepare("SELECT special FROM users WHERE id=:id");
$stmt->bindParam(":id", $person);
$stmt->execute();
$res = $stmt->fetch(PDO::FETCH_ASSOC);
if($res["special"]=="banned"){
$person = $_GET["user"];
$stmt = $conn->prepare("UPDATE users SET special=null, ban_reason=null WHERE id=:id");
$stmt->bindParam(":id", $person);
$stmt->execute();
if($stmt){
$person = getUserInfo($person)->name;
msg("$person has been unbanned");
header("Location: /admin/portal/unbanUser.php");
}else{
msg("Error unbanning $person");
reportError("Error unbanning $person in /admin/portal/manage.php");
header("Location: /admin/portal/unbanUser.php");
}
}else{
msg("$person was never banned");
header("Location: /admin/portal/unbanUser.php");
}
}
?>
<!DOCTYPE html>
<html>
<?php
$css = "/admin/portal/admin";
include "../../res/head";
?>
<body>
<?php
include "../../res/top";
?>
<div id=monoContainer>
<div class="card noHover center">
<h2>UNBAN USER</h2>
<p><?php
conn();
$stmt = $conn->prepare("SELECT * FROM users WHERE special='banned'");
$stmt->execute();
$row = $stmt->fetchAll();
if(sizeof($row)==0){
echo "<i>No banned users :D</i>";
}
foreach($row as $person){
echo "<a class=deletable href=/admin/portal/unbanUser.php?user=".$person["id"].">".$person["name"]."</a><br>";
}
?></p>
</div>
</div>
</body>
</html>

130
comments.css Normal file
View File

@@ -0,0 +1,130 @@
/* ------------- Comments ------------- */
#comments{
padding-bottom: 1em;
}
#commentWriter{
width: 90%;
margin: 0 auto;
min-height: 6em;
border: 1px solid #ddd;
border-radius: 0.3em;
background-color: #f8f8f8;
resize: none;
color: black;
position: relative;
}
/* Actual part to write the comment */
#commentEditor{
padding: 0.5em;
min-height: 3em;
margin-bottom: 2em;
}
#commentEditor:empty:before{
content: attr(placeholder);
color: #555;
}
#commentEditor:focus{
outline-width: 0;
}
/* Submit buttons etc. */
#commentWriterButtons{
position: absolute;
background-color: #f2f2f2;
width: 100%;
height: 2em;
bottom: 0;
}
#rulesReminder{
margin: calc((2em - (1em - 0.8em)) / 2) 0.3em;
font-size: 0.8em;
color: gray;
}
#rulesReminder>a{
color: gray;
}
#commentSubmitWrapper{
position: absolute;
right: 0;
height: 100%;
}
#commentSubmitWrapper>p{
display: inline;
}
#commentSubmitWrapper>button{
height: 100%;
border: none;
padding: 0 1em;
background-color: #e5e5e5;
}
#commentSubmitWrapper>button:hover{
cursor: pointer;
/* Shouldn't this be default? */
}
/* ------------- Submitted comments -------------*/
.comment{
width: 90%;
margin: 3em auto 0 auto;
}
.commentTop{
margin: 0.5em 0;
}
.commentTop>p{
display: inline;
width: 100%;
}
.commentTop>p>i{
color: #444;
margin: 0 0.2em;
}
.commentName{
color: black;
font-weight: bold;
text-decoration: none;
}
.commentName:hover{
text-decoration: underline;
}
.commentTime{
color: gray;
font-size: 0.8em;
}
.commentMiddle{
font-size: 0.99em;
overflow: hidden;
}
.commentBottom{
display: block;
height: 1em;
}
.commentReply{
color: #00d09f;
text-decoration: none;
float: right;
margin-right: 1em;
}
.commentReport{
font-size: 0.8em;
}
.commentReport, .commentReport>a{
float: left;
margin: 0.5em 0 0 0;
text-decoration: none;
color: #999;
}
.commentReport:hover, .commentReport>a:hover{
text-decoration: underline;
}
/*Highlighting if user go there by @mentions*/
.current{
background-color: white;
animation: mention;
animation-duration: 900ms;
}
@keyframes mention {
10% {background-color: white;}
50% {background-color: #fcff79;}
100% {background-color: white;}
}

80
darkTheme.css Normal file
View File

@@ -0,0 +1,80 @@
/*
The use of !important is out of sheer laziness. To fix, just create two css
documents, one for light theme and one for dark. Until then, this will have to
work.
*/
body{
background-color: #090909 !important;
color: #ccc !important;
}
#leftMobile{
background-color: #090909 !important;
}
.hamburger{
filter: invert(25%) !important;
}
#topMobile{
background-color: #090909 !important;
}
msg{
background-color: #0d0d0d !important;
color: #bcbcbc !important;
border: 1px solid #242424 !important;
}
#top, #topMobile, #userTopWrapper{
background-color: #090909 !important;
box-shadow: none !important;
border-bottom: 1px solid #242424 !important;
}
input[type=text]{
border: 0 !important;
border-bottom: 1px solid #ccc !important;
background-color: transparent;
color: #bcbcbc;
}
#searchBar, #searchBarMobile, textarea, #postEditor{
background-color: #1a1919 !important;
border: 0 !important;
color: #bcbcbc;
}
#addPost:hover, #addPostMobile:hover{
background-color: #1a1919 !important;
}
#postEditor{
border-radius: 0 !important;
}
.userTopSel{
color: inherit !important;
}
#commentWriter{
border: 1px solid #626262 !important;
color: inherit !important;
}
#commentWriterButtons, #commentEditor{
background-color: #0b0b0b !important;
}
#commentSubmitButton{
background-color: #111 !important;
}
.card{
background-color: #0b0b0b !important;
color: #bcbcbc !important;
box-shadow: none !important;
}
.card:hover:not(.noShadow):not(.noHover){
box-shadow: none !important;
border: 1px solid #626262 !important;
}
.card:not(.noShadow){
border: 1px solid #242424 !important;
box-shadow: none !important;
}
button[type="submit"]:not(#commentSubmitButton){
background-color: #111;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

51
forum/foo.php Normal file
View File

@@ -0,0 +1,51 @@
<?php
/**
* Please note that files uploaded are placed in /forum/images (even non-image
* files) because this function used to only be for images. It has since been
* updated to allow for doc files too.
*
**/
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
restrictAccess("owner");
echo("Change the file /forum/foo.php if you really want to do this");
exit();
exit();//just to be safe lol
conn();
$lipsum = "Sed facilis libero enim. Omnis molestias ut nihil a ea rem magnam repellat. Dolorum fugit quod quo ipsam qui molestiae aut. Voluptatem doloribus sint natus aut sequi illum quo. Ut est et ut odio et et totam. Et saepe quis maxime rerum et omnis qui. Tenetur sunt ratione iure atque aut blanditiis. Vitae consequuntur esse et qui. Officia sunt eum et distinctio sunt aut rem et. Excepturi nostrum et cum. Id aut delectus id sit. Sed impedit placeat in eos et qui ab. Distinctio doloremque veritatis qui velit voluptas. Velit corporis soluta similique et. Et iure enim quaerat aut qui non porro neque. Laudantium non voluptas illum error sit qui expedita. Deserunt similique officiis blanditiis voluptatibus dicta ea sunt. Deserunt aut reprehenderit ut quia minima facere. Praesentium facere laudantium nisi quasi corrupti accusantium perferendis quidem. Quo dolorem maiores iure officiis aspernatur eos. Quisquam ut excepturi facilis iusto nemo fugiat. Et sequi nostrum asperiores unde cumque perspiciatis aperiam. Pariatur adipisci eum illo quis maxime fugit consequatur. Quo sit fugiat voluptatum. Quia soluta ex ut neque aliquam aperiam. Aperiam ut ad enim. Voluptas ducimus rem fugit. Tempora autem voluptatem cum aliquid. Dolorum iure impedit cumque vel soluta dolores alias. Voluptatem rerum tempora accusantium deserunt nam voluptatem. Voluptas non cum nostrum. Enim possimus vero voluptas rem est voluptatem odit. Ea laudantium odio soluta molestias eligendi aut. Repellendus tempore et consectetur beatae praesentium. Dolorum id quis ad. Est nihil et debitis dolor laborum delectus cum aspernatur. Aliquam voluptates ipsum velit delectus laudantium. Suscipit ratione quia ea hic non veritatis eos neque. Quas quos impedit perferendis sed pariatur quisquam et. Dolores eveniet quas adipisci itaque ipsa veritatis cum nisi.";
$tipsum = "Suscipit ratione quia ea hic non veritatis eos neque. Quas quos impedit perferendis sed pariatur quisquam et. Dolores eveniet quas adipisci itaque ipsa veritatis cum nisi";
function random_pic(){
$files = glob('images/*.*');
$file = array_rand($files);
return basename($files[$file]).",";
}
for($i=1; $i<=100; $i++){
$pid = randID();
$uid = $current_user;
$sbj = "none";
$typ = "other";
$ttl = "$i: ".substr($tipsum, 0, rand(0, strlen($tipsum)));
$ctt = substr($lipsum, 0, rand(0, strlen($lipsum)));
$img = rand(0,19)<=5?random_pic():NULL;
$stmt = $conn->prepare("INSERT INTO forums (post_id, poster_id, section, type, title, content, image) VALUES (:pid, :uid, :sbj, :typ, :ttl, :ctt, :img)");
$stmt->bindParam(":pid", $pid);
$stmt->bindParam(":uid", $uid);
$stmt->bindParam(":sbj", $sbj);
$stmt->bindParam(":typ", $typ);
$stmt->bindParam(":ttl", $ttl);
$stmt->bindParam(":ctt", $ctt);
$stmt->bindParam(":img", $img);
$stmt->execute();
if(!$stmt){
msg("Error fooing posts :(");
header("Location: /forum");
}
}
msg("Success fooing posts :D");
header("Location: /forum")
?>

BIN
forum/images/7Lb0k3.docx Normal file

Binary file not shown.

BIN
forum/images/EeaU8c.docx Normal file

Binary file not shown.

BIN
forum/images/JkocQZ.docx Normal file

Binary file not shown.

BIN
forum/images/LvHBpe.docx Normal file

Binary file not shown.

BIN
forum/images/OFCtQg.docx Normal file

Binary file not shown.

BIN
forum/images/R1GF5H.docx Normal file

Binary file not shown.

BIN
forum/images/TOFPvl.docx Normal file

Binary file not shown.

BIN
forum/images/rQZFd.pdf Normal file

Binary file not shown.

41
forum/index.php Normal file
View File

@@ -0,0 +1,41 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
?>
<!DOCTYPE html>
<html>
<?php
include "../res/head";
?>
<body>
<?php include "../res/top"; ?>
<div id=container>
<div id=left>
<?php
$limit = 10;
$page = is_numeric($_GET["page"])&&$_GET["page"]>0?$_GET["page"]:1;
$start = $limit * ($page - 1);
$stmt = $conn->prepare("SELECT * FROM forums ORDER BY date DESC LIMIT $start,$limit");
$stmt->execute();
foreach($stmt->fetchAll() as $post){
makePost($post);
}
//checking if there would be results on the next page
$row = $start+$limit;
$stmt = $conn->prepare("SELECT * FROM forums ORDER BY date DESC LIMIT $row,1");
$stmt->execute();
$moreResults = $stmt->rowCount();
?>
<div id=pages>
<?php
echo $page!=1?"<div id=prevPage><a href=/forum/?page=".($page-1).">&larr;</a></div>":"<div></div>";
echo $moreResults?"<div id=nextPage><a href=/forum/?page=".($page+1).">&rarr;</a></div>":"<div></div>";
?>
</div>
</div>
<?php include $_SERVER['DOCUMENT_ROOT']."/res/notifs"; ?>
</div>
</body>
</html>

216
forum/post/index.php Normal file
View File

@@ -0,0 +1,216 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
//Deleting comments
if(isset($_GET["delc"])){
$getcstmt = $conn->prepare("SELECT * FROM comments WHERE id = :cid");
$getcstmt->bindParam(":cid", $_GET["delc"]);
$getcstmt->execute();
$comment = $getcstmt->fetch(PDO::FETCH_ASSOC);
//Putting comment into "deleted" datebase
$mcstmt = $conn->prepare("INSERT INTO deletedComments (post_id, poster_id, date, text, reports) VALUES (:post, :pstr, :date, :text, :rpts)");
$mcstmt->bindParam(":post", $comment["post_id"]);
$mcstmt->bindParam(":pstr", $comment["poster_id"]);
$mcstmt->bindParam(":date", $comment["date"]);
$mcstmt->bindParam(":text", $comment["text"]);
$mcstmt->bindParam(":rpts", $comment["reports"]);
$mcstmt->execute();
//Removing the comment from the normal database
$cstmt = $conn->prepare("DELETE FROM comments WHERE id = :cid");
$cstmt->bindParam(":cid", $_GET["delc"]);
$cstmt->execute();
//Giving feedback and redirecting
if(!$mcstmt || !$cstmt){
reportError("A comment couldn't be deleted in /forum/post/index.php");
msg("Couldn't delete comment. It has been reported for you");
}else{
msg("Comment deleted");
}
header("Location: /forum/post/?post=".$_GET["post"]);
}
//reporting comment
if(isset($_GET["repc"])){
$stmt = $conn->prepare("SELECT * FROM comments WHERE id = :id");
$id = $_GET["repc"];
$stmt->bindParam(":id", $id);
$stmt->execute();
$delc = $stmt->fetch(PDO::FETCH_OBJ);
$rep = $delc->reports;
if(strContains($rep, $current_user)){
$prevRep = true;
}else{
$prevRep = false;
$rep .= $current_user.",";
}
$stmt = $conn->prepare("UPDATE comments SET reports = :rep WHERE id = :id");
$id = $_GET["repc"];
$stmt->bindParam(":id", $id);
$stmt->bindParam(":rep", $rep);
$stmt->execute();
if($stmt){
msg($prevRep==true?"You already reported that comment.":"Comment reported");
header("Location: /forum/post/?post=".$_GET["post"]);
}else{
reportError("Error reporting comment in /forum/post/index.php - a");
msg("Error reporting comment. This error has been reported.");
header("Location: /forum/post/?post=".$_GET["post"]);
}
}
//Getting and storing the post info to echo later
$post = getPostInfo($_GET["post"]);
$poster_id = $post->poster_id;
$title = $post->title;
$content = hyperlink($post->content);
$content = decodeUserLink($post->content);
$section = $post->section=="none"?"":ucwords(str_replace("_", " ", $post->section));
$type = $post->type=="other"?"":strtolower($post->type);
$type = $section==""?ucwords($type):$type;
$section = $section==$type?"No topic":$section;
$date = $post->date;
$images = $post->image;
$poster = getUserInfo($poster_id)->name;
//Checking if the user has this post bookmarked for un/bookmarking
$stmt = $conn->prepare("SELECT * FROM bookmarks WHERE post_id = :pid AND user_id = :uid");
$stmt->bindParam(":pid", $_GET["post"]);
$stmt->bindParam(":uid", $current_user);
$stmt->execute();
$res = $stmt->fetch(PDO::FETCH_OBJ);
$bk = $res->user_id==$current_user?true:false;
//Bookmarking the post
if(isset($_GET["bkmk"]) && $_GET["bkmk"] =="t" && !$bk){
$stmt = $conn->prepare("INSERT INTO bookmarks (post_id, user_id) VALUES (:pid, :uid)");
$stmt->bindParam(":pid", $_GET["post"]);
$stmt->bindParam(":uid", $current_user);
$stmt->execute();
if($stmt){
msg("Post saved. You can find it on your account page.");
header("Location: /forum/post/?post=".$_GET["post"]);
}else{
reportError("Error while saving post in /forum/post/index.php - b");
msg("Error! It has been reported automatically.");
header("Location: /forum/post/?post=".$_GET["post"]);
}
}
//Unbookmarking the post
if(isset($_GET["bkmk"]) && $_GET["bkmk"] =="f"&&$bk){
$stmt = $conn->prepare("DELETE FROM bookmarks WHERE post_id = :pid AND user_id = :uid");
$stmt->bindParam(":pid", $_GET["post"]);
$stmt->bindParam(":uid", $current_user);
$stmt->execute();
if($stmt){
msg("Post unsaved.");
header("Location: /forum/post/?post=".$_GET["post"]);
}else{
reportError("Error unsaving post in /forum/post/index.php - c");
msg("Error! It has already been reported for you.");
header("Location: /forum/post/?post=".$_GET["post"]);
}
}
//Checking if the user has this post bookmarked
$stmt = $conn->prepare("SELECT * FROM bookmarks WHERE post_id = :pid AND user_id = :uid");
$stmt->bindParam(":pid", $_GET["post"]);
$stmt->bindParam(":uid", $current_user);
$stmt->execute();
$res = $stmt->fetch(PDO::FETCH_OBJ);
$bk = $res->user_id==$current_user?true:false;
//Reporting the post
if(isset($_GET["reportPost"])){
$post = getPostInfo($_GET["post"]);
$current = $post->reports;
if(strpos($current, $current_user) === false){
$new = $current.$current_user.",";
$stmt = $conn->prepare("UPDATE forums SET reports = :new WHERE post_id = :id");
$stmt->bindParam(":new", $new);
$stmt->bindParam(":id", $post->post_id);
$stmt->execute();
if($stmt){
msg("Post reported.");
header("Location: /forum/post/?post=".$_GET["post"]);
}else{
reportError("Error reporting post in /forum/post/index.php - d");
msg("Error reporting post. This error has been reported.");
header("Location: /forum/post/?post=".$_GET["post"]);
}
}else{
msg("You already reported this post.");
header("Location: /forum/post/?post=".$_GET["post"]);
}
}
?>
<!DOCTYPE html>
<html>
<?php
$css = '/comments';
$css2 = 'post';
include "../../res/head";
?>
<body>
<?php
include "../../res/top";
?>
<div class="container card noHover">
<div id=post>
<div class="forum card noShadow">
<div class=info>
<p onclick="document.location.href = '/search/?q=<?=$section;?>:+'; return false" class=postType><?=$section." ".$type; ?></p>
<p>Posted <?=makeDate($date);?> by <span onclick="document.location.href = '/user/?user=<?=$poster_id;?>'; return false" class=userlink><?=$poster;?></span></p>
</div>
<div class=title>
<h2><?=$title;?></h2>
</div>
<div class=content>
<p>
<?=$content;?>
<?php
if($images != NULL){
echo "<input type=checkbox id=hideImgs>
<label for=hideImgs id=hide class=noSelect>HIDE ATTACHMENTS</label>
<label for=hideImgs id=show class=noSelect>SHOW ATTACHMENTS</label>";
foreach(explode(",", substr($images, 0, -1)) as $file){
//substr gets rid of the last comma, explode makes the array
$exType = substr($file, strpos($file, '.')+1);
$docFiles = ["doc", "docx", "pdf"];
$imgFiles = ["jpg", "jpeg", "png"];
//image stuff
if(in_array($exType, $docFiles)){
echo "<iframe class='postDocPreview toggleView' src=https://docs.google.com/gview?url=http://ib.lukeogburn.com/forum/images/$file&embedded=true></iframe>";
//<embed src="file_name.pdf" width="800px" height="2100px" />
}else if(in_array($exType, $imgFiles)){
echo "<img class='postImage toggleView' src=/forum/images/$file>";
}
}
}
?>
</p>
</div>
</div>
</div>
<div class=postBottom>
<?php
if(getUserInfoByName($poster)->id == $current_user){
$datediff = time() - strtotime($date);
$mins = round($datediff / (60));
if($mins <= 5){
$editable = " | <a id=editPost href=/post/edit.php?post=".$_GET['post'].">edit</a>";
}
echo "
<p class=postActions><a id=deletePost href=/post/delete.php?post=".$_GET['post'].">delete</a>$editable</p>";
}else{
echo "<p><a href=?post=".$_GET['post']."&reportPost=true class=postReport>report</a></p>";
}
?>
<i class=material-icons><a class="postSave" href=?post=<?=$_GET['post'];?>&bkmk=<?=$bk?"f":"t";?>><?=$bk?"bookmark":"bookmark_outline";?></a></i>
</div>
</div>
<?php include "../../res/comments"; ?>
</body>
</html>

126
forum/post/post.css Normal file
View File

@@ -0,0 +1,126 @@
/* ------------- Global post ------------- */
.container{
width: 60%;
margin: 2% auto 0 auto;
color: #333;
background-color: white;
margin-bottom: 2em;
border-radius: 0.2em;
padding: 1em 2em;
line-height: 1.3em;
}
.container>*{
border-radius: 0.3em;
}
/* General forum stuff */
.forumLink{
text-decoration: none;
}
/* ------------- Post ------------- */
/* Title, username, time posted */
.title>h2{
margin: 0.5em 0;
line-height: 1.2em;
}
.info>*{
font-size: 0.75em;
color: #aaa;
margin: 0;
display: inline-block;
}
.userlink:hover, .postType:hover{
text-decoration: underline;
}
.postType{
color: #888;
font-weight: bold;
margin: 0 0.5em 0 0.2em;
}
/* Text and image */
.content>p{
margin: 0;
}
.forum.card{
margin-bottom: 1em;
}
.postImage{
margin-top: 1em;
width: 100%;
border-radius: 0.3em;
}
.postDocPreview{
margin-top: 1em;
width: 100%;
border-radius: 0.2em;
border: 1px solid #999;
height: 50vh;
}
#show:hover, #hide:hover{
cursor: pointer;
}
#hideImgs{
display: none;
}
#hideImgs ~ #hide{
display: block;
}
#hideImgs ~ #show{
display: none;
}
#hideImgs:checked ~ #hide{
display: none;
}
#hideImgs:checked ~ #show{
display: block;
}
#hideImgs ~ label{
margin-top: 2em;
color: #00d09f;
text-align: center;
font-size: 0.9em;
margin-bottom: 0;
}
#hideImgs:checked ~ .toggleView{
display: none;
}
/* Fixing tag-padding issue
.tags>p{
padding: 0em 0.5em;
}*/
/* Reporting and saving */
.postBottom{
display: block;
height: 1.5em;
font-size: 1em;
padding: 0 1em;
display: grid;
align-content: center;
grid-template-columns: 1fr 1fr;
}
.postReport, .postActions{
margin: 0;
font-size: 0.8em;
color: #999;
}
.postReport{
color: #922;
text-decoration: none;
}
.postActions>a{
color: #888;
text-decoration: none;
}
.postActions>a:hover,.postReport:hover{
text-decoration: underline;
}
.postSave{
color: inherit;
text-decoration: none;
float: right;
}
.postSave>*{
float: right;
}

405
globalFuncs.php Normal file
View File

@@ -0,0 +1,405 @@
<?php
//This fixes the "headers already sent" issue noticed in the msg system
ob_start();
//error handling
function errorHandler($n, $m, $f, $l) {
if($n > 10){
reportError("Level $n error: $m in file \"$f\" on line $l");
}
}
set_error_handler('errorHandler');
//msg handling (msg delivered in /res/top)
if(isset($_COOKIE["IB_MSG"])){
$msg = $_COOKIE["IB_MSG"];
setcookie("IB_MSG", $_COOKIE["IB_MSG"], $_SERVER['REQUEST_TIME']-3600, "/");
}else{
$msg = NULL;
}
require "conn.php";
//conn.php used to be part of this file, but I don't want to accidentally upload it to github
//Verifying user with cookie
if(isset($_COOKIE["IB_SESSION"])){
$cookie = $_COOKIE["IB_SESSION"];
conn();
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM login_tokens WHERE user_id = :id");
$stmt->bindParam(":id", $_COOKIE["IB_ID"]);
$stmt->execute();
$row = $stmt->fetchAll();
$GLOBALS["verified"] = $verified = false;
for($i=0; $i<sizeof($row); $i++){
$token = $row[$i]["token"];
if(password_verify($cookie, $token)){
$GLOBALS["verified"] = $verified = true;
// both $current_user and $GLOBALS["current_user"]
// are used later, so don't delete either one
$current_user = $GLOBALS["current_user"] = $_COOKIE["IB_ID"];
}
}
}else{
header("Location: /user/login.php");
}
if(!$GLOBALS["verified"]){
header("Location: /user/login.php");
}
function getUserInfo($id){
conn();
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM users WHERE id = :id");
$id = strval($id); //Just making sure
$stmt->bindParam(":id", $id);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_OBJ);
if($result==NULL){
return false;
}else{
return $result;
}
}
function getUserInfoByName($name){
conn();
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM users WHERE name = :name");
$stmt->bindParam(":name", $name);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_OBJ);
if($result==NULL){
return false;
}else{
return $result;
}
}
//Making sure that the user isn't banned
if(getUserInfo($current_user)->special == "banned" && $GLOBALS["page"] != "banned"){
header("Location: /user/banned.php");
}
function strContains($haystack, $needle){
if(strpos($haystack, $needle)!==false){
return true;
}else{
return false;
}
}
function verifyID($pid){
conn();
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM forums WHERE post_id = :pid");
$stmt->bindParam(":pid", $pid);
$stmt->execute();
$forums = $stmt->fetch(PDO::FETCH_OBJ)->post_id;
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM forums WHERE image = :pid");
$stmt->bindParam(":pid", $pid);
$stmt->execute();
$images = $stmt->fetch(PDO::FETCH_OBJ)->image;
return ($forums!=NULL||$images!=NULL)?false:true;
}
function randID($length = 7) {
do{
if(function_exists("random_bytes")){
$bytes = random_bytes(ceil($length/2));
}elseif(function_exists("openssl_random_pseudo_bytes")){
$bytes = openssl_random_pseudo_bytes(ceil($length/2));
}else{
throw new Exception("No cryptographically secure random function available.");
}
$x = substr(bin2hex($bytes), 0, $length);
$id = gmp_strval(gmp_init($x, 36), 62);
} while(!verifyID($id));
return $id;
}
function makeDate($date){
$date = strtotime($date);
$now = $_SERVER['REQUEST_TIME'];
$datediff = $now - $date;
$secs = round($datediff);
$mins = round($datediff / (60));
$hours = round($datediff / (60 * 60));
$days = round($datediff / (60 * 60 * 24));
if($secs<60){
if($secs == 1){
$date = $secs." second ago";
}else{
$date = $secs." seconds ago";
}
}else if($mins<60){
if($mins == 1){
$date = $mins." minute ago";
}else{
$date = $mins." minutes ago";
}
}else if($days<1){
if($hours == 1){
$date = $hours." hour ago";
}else{
$date = $hours." hours ago";
}
}else if($days < 8){
if($days == 1){
$date = " yesterday";
}else{
$date = $days." days ago";
}
}else{
$date = date("M j", $date);
}
return $date;
}
function verifyUser($level, $id = NULL){
if($id == NULL){
$id = $GLOBALS["current_user"] ;
}
$oldLevel = $level;
switch($level){
case "admin":
$level = 1;
break;
case "owner";
$level = 2;
break;
default:
$level = 0;
break;
}
conn();
$stmt = $GLOBALS['conn']->prepare("SELECT special FROM users WHERE id = :id");
$stmt->bindParam(":id", $id);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_OBJ);
$extra = $row->special;
switch($extra){
case "admin":
$userLevel = 1;
break;
case "owner":
$userLevel = 2;
break;
default:
$userLevel = 0;
}
if($userLevel>=$level){
echo "<!-- ".getUserInfo($id)->name." verified as an $oldLevel -->\n";
return true;
}else{
return false;
}
}
function restrictAccess($level){
if(!verifyUser($level)){
$current_user = $GLOBALS["current_user"];
msg("You don't have access to that file");
$username = getUserInfo($current_user)->name;
$file = getcwd()."/".basename(__FILE__);
reportError("User $current_user ($username) tried to access $file");
header("Location: /");
}
}
function alertDelete($id){
conn();
$stmt = $GLOBALS['conn']->prepare("DELETE FROM alerts WHERE id = :id");
$stmt->bindValue(":id", $id);
$stmt->execute();
if(!$stmt){
reportError("Error in globalFuncs:alertDelete - stmt failed");
msg("Error removing mention from sidebar. This has been reported for you.");
}
}
function alertInsert($er, $ee, $id){
if($er == NULL){
$er = $GLOBALS["current_user"];
}
conn();
$stmt = $GLOBALS['conn']->prepare("SELECT id FROM comments ORDER BY id DESC LIMIT 1");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_OBJ);
$maxID = intval($result->id);
$maxID++;
$stmt = $GLOBALS['conn']->prepare("INSERT INTO alerts (id, mentioner, mentionee, post_id) VALUES (:mid, :er, :ee, :id)");
$stmt->bindValue(":mid", $maxID);
$stmt->bindValue(":er", $er);
$stmt->bindValue(":ee", $ee);
$stmt->bindValue(":id", $id);
$stmt->execute();
if(!$stmt){
reportError("Issue in globalFuncs:alertInsert - stmt failed");
msg("Error in the mention system - ".getUserInfo($ee)->name." could not be alerted to your mention.");
}
}
function hyperSearch($text){
preg_match_all("#((((-|_){0,}\w)+\.([a-zA-Z]+){2,})|((((http)|(https)):\/\/){1}((-|_){0,}\w)+\.([a-zA-Z]+){2,}))((\w+|-|_|\/|\.)+){0,}#", $text, $match);
if($match[0]==NULL){
return false;
}else{
return $match[0];
}
}
function hyperlink($text){
$link = hyperSearch($text);
if($link != false){
foreach($link as $link){
$content = "<a class=userRefLink target=_BLANK href=".$link.">".$link."</a>";
$text = str_replace($link, $content, $text);
}
}
return $text;
}
function linkSearch($text){
if(strContains($text, "@")){
preg_match_all("#(?<=@)(.?)(?:[\w\-_])+#", $text, $match);
return $match[0];
}else{
return false;
}
}
function encodeUserLink($info, $er = NULL, $id = NULL){
// Searching for user links
$link = linkSearch($info);
if($link != false){
$link = array_filter($link);
foreach($link as $thing){
$user = getUserInfoByName(strval($thing));
if($user!=false){
$info = str_replace($thing, $user->id, $info);
//For the mention (alert) system
alertInsert($er, $user->id, $id);
}else if(getUserInfo($thing) != false){
//For the mention (alert) system
alertInsert($er, $thing, $id);
}
}
}
return $info;
}
function decodeUserLink($info){
$link = linkSearch($info);
if($link != false){
$link = array_filter($link);
foreach($link as $thing){
$user = getUserInfo(strval($thing));
if($user!=false){
$content = "<a class=userRefLink href=/user/?user=".$user->id.">".$user->name."</a>";
$info = str_replace($thing, $content, $info);
}else if(!$user && getUserInfoByName(strval($thing))!=false){
$user = getUserInfoByName(strval($thing));
$content = "<a class=userRefLink href=/user/?user=".$user->id.">".$user->name."</a>";
$info = str_replace($thing, $content, $info);
}
}
}
return $info;
}
function decodeUserNoLink($info){
$link = linkSearch($info);
if($link != false){
$link = array_filter($link);
foreach($link as $thing){
$user = getUserInfo(strval($thing));
if($user!=false){
$content = $user->name;
$info = str_replace($thing, $content, $info);
}else if(!$user && getUserInfoByName(strval($thing))!=false){
$user = getUserInfoByName(strval($thing));
$content = $user->name;
$info = str_replace($thing, $content, $info);
}
}
}
return $info;
}
function reportError($issue){
$reporter = $_COOKIE["IB_ID"];
$stmt = $GLOBALS['conn']->prepare("INSERT INTO issue_tracker (reporter, comment, auto) VALUES (:reporter, :issue, :auto)");
$stmt->bindValue(":reporter", $reporter);
$stmt->bindValue(":issue", $issue);
$stmt->bindValue(":auto", true);
$result = $stmt->execute();
}
function msg($text){
// msg is "delivered" in /res/top
setcookie("IB_MSG", $text, $_SERVER['REQUEST_TIME'] + 60, "/", NULL, true, true);
}
function getPostInfo($post){
conn();
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM forums WHERE post_id = :id");
$stmt->bindParam(":id", $post);
$stmt->execute();
return $stmt->fetch(PDO::FETCH_OBJ);
}
function makePost($post){
if(gettype($post)=="object"){
//converting object into array if needed, so it can be used here
$post = json_decode(json_encode($post), True);
}
//$img = $post["image"]==NULL?"":"<img class=postPrevImg src=/forum/images/".substr($post["image"], 0, strpos($post["image"], ",")).">";
//setting some defaults
$img = $clp = $imgClass = NULL;
$file = substr($post["image"], 0, strpos($post["image"], ","));
$exType = substr($file, strpos($file, '.')+1);
$docFiles = ["doc", "docx", "pdf"];
$imgFiles = ["jpg", "jpeg", "png"];
//image stuff
if(in_array($exType, $docFiles)){
$clp = "<img class='postPrevImg clip' src=/res/i/clip.png>";
}else if(in_array($exType, $imgFiles)){
$img = "<img class=postPrevImg src=/forum/images/$file>";
$imgClass = " image";
}
$ellipsisT = strlen($post["title"])>75?"...":"";
$ellipsisC = strlen($post["content"])>400?"...":"";
$section = $post["section"]=="none"?"":ucwords($post["section"]);
$type = $post["type"]=="other"?"":strtolower($post["type"]);
$type = $section==""?ucwords($type):$type;
$section = $section==$type?"No topic":$section;
echo "\n<a href=/forum/post?post=".$post["post_id"]." class=forumLink>
<div class='forum card".$imgClass."'>
<div class=left>
<div class=info>
<p onclick=\"document.location.href = '/search?q=".strtolower($post["section"]).":+'; return false\" class=postType>".$section." ".$type."</p>
<p>Posted ".makeDate($post["date"])." by <span onclick=\"document.location.href = '/user/?user=".$post["poster_id"]."'; return false\" class=userlink>".getUserInfo($post["poster_id"])->name."</span></p>
</div>
<div class=title>
<h2>".substr($post["title"], 0, 75).$ellipsisT.$clp."</h2>
</div>
<div class=preview>
<p>".decodeUserNoLink(substr(strip_tags($post["content"]), 0, 400)).$ellipsisC."</p>
</div>
</div>
<div class=right>
".$img."
</div>
</div>
</a>";
}
?>

1
index.php Normal file
View File

@@ -0,0 +1 @@
<?php header('Location: /forum') ?>

202
mobile.css Normal file
View File

@@ -0,0 +1,202 @@
/* ---------- Mobile CSS ---------- */
/**
*
* The method used to move elements is to use a media query to hide the element,
* and another media query to show one. This is basically a toggle.
*
**/
.mobileOnly{
display: none;
}
@media (max-width: 1000px){
.mobileOnly{
display: block !important;
width: 90vw;
margin: 1em auto !important;
}
#monoContainer{
margin-top: 3em;
}
#container{
margin-top: 5vw !important;
display: block;
width: 100%;
}
#container.keepRight{
display: grid !important;
}
#container>#left{
width: 90vw;
margin-left: auto;
margin-right: auto;
}
#right{
display: none;
}
.keepRight>#right{
display: block;
}
#results, #monoContainer{
width: 85vw !important;
margin-left: auto;
margin-right: auto;
}
.card{
margin-bottom: 1em;
}
#top{
display: none;
}
#topMobile{
display: grid;
grid-template-columns: 1fr 3fr 1fr;
width: 100%;
text-align: center;
height: 2.1em;
align-items:center;
padding: 2% 0;
margin: 0 auto;
background-color: white;
position: fixed;
top: 0;
z-index: 2;
box-shadow: 0 1px 2px #ddd;
text-align: center;
align-items: middle;
}
#topMobile>a{
margin-left: auto;
margin-right: auto;
}
#logoMobile{
height: 2em;
}
.hamburger{
width: 2em;
filter: opacity(0.7);
}
.hamburger:hover{
cursor: pointer;
}
/*Actual checkbox toggle*/
#hamCheck{
display: none;
}
#hamCheck:checked ~ p{
color: red;
}
#leftMobile{
position: fixed;
top: 0;
left: -82vw;
z-index: 999;
padding-top: 5vh;
background-color: white;
width: 80vw;
height: 100vh;
align-items: middle;
text-align: center;
box-shadow: 1px 0 2px #ddd;
transition-duration: 100ms;
overflow-y: auto;
}
#hamCheck:checked ~ #leftMobile{
left: 0;
}
#hamCheck:checked ~ #leftMobile>label>#hamburgerInLeft{
display: block;
position: fixed;
left: calc(80vw - 2.6em);
top: 4vh;
filter: opacity(0.6);
transition: 200ms;
}
#leftMobile>#right>.card{
box-shadow: none;
padding: 0.5em;
width: 70%;
margin: 0 auto;
}
#leftMobile>#right>.card:last-of-type{
margin-bottom: 100px;
}
#accountMobile{
border-radius: 50%;
width: 35%;
}
#searchMobile{
width: calc(70% - 20px);
margin: 0 auto;
color: #444;
}
#searchBarMobile{
width: 95%;
font-size: 1em;
background-color: #f4f4f4;
border: 0;
padding: 5px 10px;
border-radius: 0.3em;
}
#searchBarMobile::-webkit-input-placeholder {
color: #999 !important;
}
#searchBarMobile:-moz-placeholder { /* Firefox 18- */
color: #999 !important;
}
#searchBarMobile::-moz-placeholder { /* Firefox 19+ */
color: #999 !important;
}
#searchBarMobile:-ms-input-placeholder {
color: #999 !important;
}
#searchFormMobile{
width: 100%;
}
/* Add post button */
#addPostMobile{
cursor: pointer;
margin: 1em auto;
border-radius: 0.3em;
width: 70%;
font-size: 1.2em;
}
#addPostMobile>a{
color: #00d09f;
display: block;
text-decoration: none;
padding: 0.5em 1em;
}
#addPostMobile:hover{
background-color: #f4f4f4;
}
/* User page posts/saved thing */
#userTopWrapper{
box-shadow: 0 2px 3px #ddd !important;
top: 0.1em;
z-index: 3;
}
/* For the /forum/post s */
.container{
margin: 5vh auto !important;
width: 90vw !important;
max-width: 100%;
padding: 0 !important;
}
#content>p>img{
width: 100%;
}
#comments{
padding-top: 1em;
}
}
@media (min-width: 1001px){
.mobile{
display: none;
}
}

178
post/common.css Normal file
View File

@@ -0,0 +1,178 @@
/* ------------- Global post ------------- */
.container{
width: 60%;
margin: 2% auto 0 auto;
color: #333;
padding: 1em 2em;
line-height: 1.3em;
}
.container>*{
border-radius: 0.3em;
}
/* ------------- Post ------------- */
/* Title, username, time posted */
.editor{
border: none;
border-bottom: 1px solid #ddd;
border-radius: 0.2em;
outline-width: 0;
resize: none;
font-family: 'Montserrat', sans-serif;
font-weight: bold;
}
.title{
width: calc(100% - 0.4em);
font-size: 1.5em;
font-weight: bold;
padding: 0.2em;
font-family: 'Montserrat', sans-serif;
}
#submitPost{
font-size: 1em;
color: #00d09f;
border: 1px solid #00d09f;
border-radius: 0.2em;
background-color: white;
padding: 0.5em 1em;
margin: 2em auto 0 auto;
display: block;
}
#submitPost:hover{
cursor: pointer;
}
.postType{
color: #888;
font-weight: bold;
margin: 0 0.5em 0 0.2em;
}
/* Text and image */
.content>p{
margin: 0;
}
.card{
padding: 2em 4em;
}
/* ------------- Post editor ------------- */
.title{
margin-bottom: 0.3em;
}
/* Actual part to write the post */
#postWriter{
background-color: white;
}
#postEditor{
padding: 0.5em;
width: calc(100% - 1em);
min-height: 3em;
}
#postEditor:empty:before{
content: attr(placeholder);
color: #777;
}
#postEditor:focus{
outline-width: 0;
}
#tagsAdder{
margin-top: 2em;
}
#postRadios{
text-align: center;
margin-top: 3em;
}
/*Images adder*/
input[type=file]{
display: none;
}
label[for=postImg]{
margin: 1em 0;
padding: 1.5em 0;
display: block;
text-align: center;
border: 2px dashed #bbb;
border-radius: 0.3em;
color: #444;
}
.postTitle{
margin-top: 2em;
font-size: 1.2em;
}
label:hover{
cursor: pointer;
}
input[type=radio]{
display: none;
}
input[type=radio]:checked + label{
color: #00d09f;
}
label.typeLabel:not(:last-of-type), label.tagLabel:not(:last-of-type){
margin-right: 2em;
}
/*Previously had images*/
.postImage{
margin-top: 1em;
width: 100%;
border-radius: 0.3em;
}
.postDocPreview{
margin-top: 1em;
width: 100%;
border-radius: 0.2em;
border: 1px solid #999;
height: 50vh;
}
#show:hover, #hide:hover{
cursor: pointer;
}
#hideImgs{
display: none;
}
#hideImgs ~ #hide{
display: block;
}
#hideImgs ~ #show{
display: none;
}
#hideImgs:checked ~ #hide{
display: none;
}
#hideImgs:checked ~ #show{
display: block;
}
#hideImgs ~ label{
margin-top: 2em;
color: #00d09f;
text-align: center;
font-size: 0.9em;
margin-bottom: 0;
}
#hideImgs:checked ~ img{
display: none;
}
@media (max-width: 1000px){
.container{
width: 90vw;
padding: 0;
margin-top: 2em;
}
#post{
padding: 1em 2em;
}
label{
margin-right: 0 !important;
margin-bottom: 5px;
text-align: center;
display: block;
list-style-type: none;
}
}

110
post/delete.php Normal file
View File

@@ -0,0 +1,110 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
//Making sure that the user is allowed to delete the post
if(getPostInfo($_GET["post"])->poster_id != $current_user && !verifyUser("admin")){
msg("You are not the owner of that post.");
header("Location: /forum/post?post=".$_GET["post"]);
exit(); //needed for some reason
}else{
conn();
//Moving images/documents
$getfstmt = $conn->prepare("SELECT image FROM forums WHERE post_id = :pid");
$getfstmt->bindParam(":pid", $_GET["post"]);
$getfstmt->execute();
$images = $getfstmt->fetch(PDO::FETCH_ASSOC);
if(count($images)>0 && $images["image"] != NULL){
$images = explode(",", substr($images["image"], 0, -1));
$poster = getPostInfo($_GET["post"])->poster_id;
$dir = $_SERVER['DOCUMENT_ROOT']."/deletedContent/$poster/";
if(!is_dir($dir)){
mkdir($dir);
}
mkdir($dir.$_GET["post"]);
foreach($images as $file){
$oldName = $_SERVER['DOCUMENT_ROOT']."/forum/images/".$file;
$newName = $dir.$_GET["post"]."/".$file;
rename($oldName, $newName);
if(!file_exists($newName)){
msg("Unable to delete post");
header("Location: /forum/post/?post=".$_GET["post"]);
exit(); //needed for some reason
}
}
}
//Putting post into "deleted" database
$post = getPostInfo($_GET["post"])->post_id;
$pstr = getPostInfo($_GET["post"])->poster_id;
$sctn = getPostInfo($_GET["post"])->section;
$type = getPostInfo($_GET["post"])->type;
$date = getPostInfo($_GET["post"])->date;
$tags = getPostInfo($_GET["post"])->tags;
$titl = getPostInfo($_GET["post"])->title;
$cont = getPostInfo($_GET["post"])->content;
$imag = getPostInfo($_GET["post"])->image;
$rprt = getPostInfo($_GET["post"])->reports;
$mfstmt = $conn->prepare("INSERT INTO deletedForums (post_id, poster_id, section, type, date, tags, title, content, image, reports) VALUES (:post, :pstr, :sctn, :type, :date, :tags, :titl, :cont, :imag, :rprt)");
$mfstmt->bindParam(":post", $post);
$mfstmt->bindParam(":pstr", $pstr);
$mfstmt->bindParam(":sctn", $sctn);
$mfstmt->bindParam(":type", $type);
$mfstmt->bindParam(":date", $date);
$mfstmt->bindParam(":tags", $tags);
$mfstmt->bindParam(":titl", $titl);
$mfstmt->bindParam(":cont", $cont);
$mfstmt->bindParam(":imag", $imag);
$mfstmt->bindParam(":rprt", $rprt);
$mfstmt->execute();
//post pstr date text rpts
$getcstmt = $conn->prepare("SELECT * FROM comments WHERE post_id = :pid");
$getcstmt->bindParam(":pid", $_GET["post"]);
$getcstmt->execute();
$comments = $getcstmt->fetchAll();
$mcstmt = $conn->prepare("INSERT INTO deletedComments (post_id, poster_id, date, text, reports) VALUES (:post, :pstr, :date, :text, :rpts)");
foreach($comments as $comment){
$mcstmt->bindParam(":post", $comment["post_id"]);
$mcstmt->bindParam(":pstr", $comment["poster_id"]);
$mcstmt->bindParam(":date", $comment["date"]);
$mcstmt->bindParam(":text", $comment["text"]);
$mcstmt->bindParam(":rpts", $comment["reports"]);
$mcstmt->execute();
}
if(count($comments) == 0){
$mcstmt = true;
}
//Making sure the post was moved correctly
if(!$mfstmt || !$mcstmt){
msg("Post could not be deleted.");
header("Location: /forum/post/?post=".$_GET["post"]);
exit(); //just in case
}
//Deleting content from the original databases
$fstmt = $conn->prepare("DELETE FROM forums WHERE post_id = :pid");
$fstmt->bindParam(":pid", $_GET["post"]);
$fstmt->execute();
$cstmt = $conn->prepare("DELETE FROM comments WHERE post_id = :pid");
$cstmt->bindParam(":pid", $_GET["post"]);
$cstmt->execute();
$bstmt = $conn->prepare("DELETE FROM bookmarks WHERE post_id = :pid");
$bstmt->bindParam(":pid", $_GET["post"]);
$bstmt->execute();
//Feedback msg and redirection
if($fstmt && $cstmt && $bstmt){
msg("Post deleted.");
header("Location: /forum");
}else{
reportError("Error deleting post");
msg("There was an error deleting your post. It has been reported.");
header("Location: /forum/post?post=".$_GET["post"]);
}
}
?>

154
post/edit.php Normal file
View File

@@ -0,0 +1,154 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
$post = getPostInfo($_GET["post"]);
$GLOBALS["post"] = $post;
if($post->poster_id!=$current_user){
msg("What if someone did that to you?");
header("Location: /forum/post/?post=".$_GET["post"]);
}
$datediff = time() - strtotime($post->date);
$mins = round($datediff / (60));
if($mins > 5){
msg("You can't edit that post.");
header("Location: /forum/post/?post=".$_GET["post"]);
}
function checked($type, $value){
return $GLOBALS["post"]->$type==$value?"checked":"";
}
$imgArray = $post->image==NULL?"":"\"".str_replace(",", "\", \"",substr($post->image,0,-1))."\"";
?>
<!DOCTYPE html>
<html>
<?php
$css = "common";
include $_SERVER['DOCUMENT_ROOT']."/res/head";
?>
<body>
<?php include $_SERVER['DOCUMENT_ROOT']."/res/top"; ?>
<form method=POST action=submitEdit.php enctype=multipart/form-data>
<div class="container">
<div id=post class="card noHover">
<div class="forum">
<input type=text class="editor title" name=title placeholder="Title goes here" value="<?=$post->title?>" autocomplete=off>
<div class=content>
<div id=postWriter>
<div contentEditable=true id="postEditor" name="contentPlaceholder" placeholder="Words go here" class=editor onkeyup=loadContent()><?=$post->content?></div>
<textarea id="contentSubmitter" style="display:none" name=content></textarea>
<script>
function loadContent(){
document.getElementById("contentSubmitter").value = document.getElementById("postEditor").innerHTML;
}
</script>
</div>
</div>
<div id=imageDiv>
<input id=postImg class=edit type=file name=images[] onchange=fileUploadCounter() multiple>
<label id=forImg for=postImg>Add Photos/Files<br><small>(PNG, JPG, JPEG, DOC, DOCX, PDF)</small></label>
</div>
<script>
document.addEventListener("DOMContentLoaded", function(event){
var i = 0;
if(i==0){
text = "<?=$post->content?>";
document.getElementById("postEditor").innerHTML = text;
document.getElementById("contentSubmitter").value = text;
i = 21; //making it only run once
}
});
var fileUploadCounter = function(){
var files = document.getElementById("postImg").files.length;
if(files != 0) {
document.getElementById("forImg").innerHTML = files + " files selected";
}
};
</script>
</div>
<div class=content>
<?php
if($post->image != NULL){
echo "<input type=checkbox id=hideImgs>
<label for=hideImgs id=hide class=noSelect>HIDE ATTACHMENTS</label>
<label for=hideImgs id=show class=noSelect>SHOW ATTACHMENTS</label>";
$i=1;
foreach(explode(",", substr($post->image, 0, -1)) as $file){
//substr gets rid of the last comma, explode makes the array
$exType = substr($file, strpos($file, '.')+1);
$docFiles = ["doc", "docx", "pdf"];
$imgFiles = ["jpg", "jpeg", "png"];
//image stuff
if(in_array($exType, $docFiles)){
echo "<iframe class='postDocPreview toggleView' src=https://docs.google.com/gview?url=http://ib.lukeogburn.com/forum/images/$file&embedded=true></iframe>";
//<embed src="file_name.pdf" width="800px" height="2100px" />
}else if(in_array($exType, $imgFiles)){
echo "<img class='postImage toggleView' src=/forum/images/$file>";
}
}
}
?>
<!-- changing the order of posts
<input id=orderedImgs type=text name=orderedImgs style=display:none>
<script>
var imgArray = [<?=$imgArray?>];
var number = function(img){
if(imgArray.indexOf(img) > -1){
//remove it from the array if it exists
imgArray.splice(imgArray.indexOf(img), 1);
}
imgArray.push(img);
imgID = "num"+imgArray[0].replace(/\./g, "");
for(var i = 0; i < imgArray.length; i++){
document.getElementById("num"+imgArray[i].replace(/\./g, "")).innerHTML = i+1;
}
document.getElementById("orderedImgs").value = imgArray.join("-").replace(/\./g, "");
}
</script>-->
</div>
<div id=postRadios>
<p class=postTitle>Subject</p>
<?php
$classes = file_get_contents($_SERVER['DOCUMENT_ROOT']."/res/classes");
$classes = array_filter(explode(",", $classes));
$num = 1;
foreach($classes as $class){
echo "<input name=section value=$class type=radio id=class$num ".checked('section',$class).">
<label class=tagLabel for=class$num>".ucwords(str_replace('_', ' ', $class))."</label>";
$num++;
}
?>
<input name=section value=none type=radio id=none <?=checked("section","none")?>>
<label class=tagLabel for="none">None</label>
<!--------------------------------------------------------------->
<p class=postTitle>Post type</p>
<input name=type value=notes type=radio id=type1 <?=checked("type","notes")?>>
<label class=typeLabel for="type1">Notes</label>
<input name=type value=question type=radio id=type2 <?=checked("type","question")?>>
<label class=typeLabel for="type2">Quesion</label>
<input name=type value=humor type=radio id=type3 <?=checked("type","humor")?>>
<label class=typeLabel for="type3">Humor</label>
<input name=type value=resource type=radio id=type4 <?=checked("type","resource")?>>
<label class=typeLabel for="type4">Resource</label>
<input name=type value=other type=radio id=type5 <?=checked("type","other")?>>
<label class=typeLabel for="type5">Other</label>
</div>
</div>
<div id=rules class="forum card noHover">
<h3>Rules:</h3>
<?php require $_SERVER['DOCUMENT_ROOT']."/res/rules"; ?>
<input type=text name=pid value=<?=$_GET["post"]?> style="display:none;">
<button type=submit id=submitPost>I understand the rules - Save!</button>
</div>
</div>
</form>
</body>
</html>

74
post/index.php Normal file
View File

@@ -0,0 +1,74 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
?>
<!DOCTYPE html>
<html>
<?php
$css = "common";
include $_SERVER['DOCUMENT_ROOT']."/res/head";
?>
<body>
<?php include $_SERVER['DOCUMENT_ROOT']."/res/top"; ?>
<form method=POST action=submitPost.php enctype=multipart/form-data>
<div class="container">
<div id=post class="card noHover">
<div class="forum">
<input type=text class="editor title" name=title placeholder="Title goes here" autocomplete=off required>
<div class=content>
<div id=postWriter>
<div contentEditable=true id="postEditor" name="contentPlaceholder" placeholder="Words go here" class=editor onkeyup=loadContent()></div>
<textarea id="contentSubmitter" style="display:none" name=content></textarea>
<script>
function loadContent(){
document.getElementById("contentSubmitter").value = document.getElementById("postEditor").innerHTML;
}
</script>
</div>
</div>
<div id=imageDiv>
<input id=postImg class=edit type=file name=images[] onchange=fileUploadCounter() accept=".png,.jpg,.jpeg,.doc,.docx,.pdf" multiple>
<label id=forImg for=postImg>Add Photos/Files<br> <small>(PNG, JPG, JPEG, DOC, DOCX, PDF)</small></label>
</div>
<script>
var fileUploadCounter = function(){
var files = document.getElementById("postImg").files.length;
if(files != 0) {
document.getElementById("forImg").innerHTML = files + " files selected";
}
};
</script>
</div>
<div id=postRadios>
<p class=postTitle>Subject</p>
<?php
$classes = file_get_contents($_SERVER['DOCUMENT_ROOT']."/res/classes");
$classes = array_filter(explode(",", $classes));
$num = 1;
foreach($classes as $class){
echo "<input name=section value=$class type=radio id=class$num>
<label class=tagLabel for=class$num>".ucwords(str_replace("_", " ", $class))."</label>";
$num++;
}
?>
<input name=section value=none type=radio id=none checked><label class=tagLabel for=none>None</label>
<p class=postTitle>Post type</p>
<input name=type value=notes type=radio id=type1><label class=typeLabel for="type1">Notes</label>
<input name=type value=question type=radio id=type2><label class=typeLabel for="type2">Quesion</label>
<input name=type value=humor type=radio id=type3><label class=typeLabel for="type3">Humor</label>
<input name=type value=resource type=radio id=type4><label class=typeLabel for="type4">Resource</label>
<input name=type value=other type=radio id=type5 checked><label class=typeLabel for="type5">Other</label>
</div>
</div>
<div id=rules class="forum card noHover">
<h3>Rules:</h3>
<?php require $_SERVER['DOCUMENT_ROOT']."/res/rules"; ?>
<button type=submit id=submitPost>I understand the rules - Submit!</button>
</div>
</div>
</form>
</body>
</html>

76
post/submitEdit.php Normal file
View File

@@ -0,0 +1,76 @@
<?php
/**
* Please note that files uploaded are placed in /forum/images (even non-image
* files) because this function used to only be for images. It has since been
* updated to allow for doc files too.
*
**/
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
$pid = $_POST["pid"];
$sbj = $_POST["section"];
$typ = $_POST["type"];
$ttl = $_POST["title"];
$ctt = encodeUserLink($_POST["content"]);
$file = $_FILES["images"];
$oldImg = $conn->prepare("SELECT image FROM forums WHERE post_id = :pid");
$oldImg->bindParam(":pid", $pid);
$oldImg->execute();
$oldImg = $oldImg->fetch(PDO::FETCH_ASSOC);
//$oimg = $_POST["orderedImgs"]==""?NULL:$_POST["orderedImgs"];
//if($oimg != NULL){
//$oimg = str_replace("-", ",", $oimg).",";
//$oimg = str_replace("jpg", ".jpg", $oimg);
//$oimg = str_replace("jpeg", ".jpeg", $oimg);
//$oimg = str_replace("png", ".png", $oimg);
//}
if($file["name"][0]!=NULL){
for($i=0; $i<sizeof($file["name"]); $i++){
$ext = explode('.', $file["name"][$i]);
$ext = strtolower($ext[sizeof($ext)-1]);
$allowedExt = array('jpg', 'jpeg', 'png', 'doc', 'docx', 'pdf');
if(in_array($ext, $allowedExt)){
if(!$file["error"][$i]){
$imgDest = randID().".".$ext;
$img .= $imgDest.",";
$dest = $_SERVER['DOCUMENT_ROOT']."/forum/images/".$imgDest;
move_uploaded_file($file["tmp_name"][$i], $dest);
}else{
echo "Error uploading file";
exit();
}
}else{
msg("Bad file type.");
header("Location: /post/edit.php?post=$pid");
exit(); //this is needed for some reason
}
}
}else{
$img = NULL;
}
$oimg = implode(",", $oldImg).$img;
echo $oImg;
//exit();
$stmt = $conn->prepare("UPDATE forums SET section = :scn, type = :typ, title = :ttl, content = :ctt, image = :img WHERE post_id = :pid");
$stmt->bindParam(":scn", $sbj);
$stmt->bindParam(":typ", $typ);
$stmt->bindParam(":ttl", $ttl);
$stmt->bindParam(":ctt", $ctt);
$stmt->bindParam(":img", $oimg);
$stmt->bindParam(":pid", $pid);
$stmt->execute();
if($stmt){
msg("Edits saved.");
header("Location: /forum/post/?post=$pid");
}else{
reportError("Error submitting post edit");
msg("Something's broken. It has been reported.");
header("Location: /forum/post/?post=$pid");
}
?>

62
post/submitPost.php Normal file
View File

@@ -0,0 +1,62 @@
<?php
/**
* Please note that files uploaded are placed in /forum/images (even non-image
* files) because this function used to only be for images. It has since been
* updated to allow for doc files too.
*
**/
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
$pid = randID();
$uid = $current_user;
$sbj = $_POST["section"];
$typ = $_POST["type"];
$ttl = $_POST["title"];
$ctt = hyperLink($_POST["content"], $uid, $pid);
$ctt = encodeUserLink($ctt, $uid, $pid);
$file = $_FILES["images"];
if($file["name"][0]!=NULL){
for($i=0; $i<sizeof($file["name"]); $i++){
$ext = explode('.', $file["name"][$i]);
$ext = strtolower($ext[sizeof($ext)-1]);
$allowedExt = array('jpg', 'jpeg', 'png', 'doc', 'docx', 'pdf');
if(in_array($ext, $allowedExt)){
if(!$file["error"][$i]){
$imgDest = randID().".".$ext;
$img .= $imgDest.",";
$dest = $_SERVER['DOCUMENT_ROOT']."/forum/images/".$imgDest;
move_uploaded_file($file["tmp_name"][$i], $dest);
}else{
echo "Error uploading file";
exit();
}
}else{
msg("Bad file type.");
header("Location: /post");
exit(); //this is needed for some reason
}
}
}else{
$img = NULL;
}
$stmt = $conn->prepare("INSERT INTO forums (post_id, poster_id, section, type, title, content, image) VALUES (:pid, :uid, :sbj, :typ, :ttl, :ctt, :img)");
$stmt->bindParam(":pid", $pid);
$stmt->bindParam(":uid", $uid);
$stmt->bindParam(":sbj", $sbj);
$stmt->bindParam(":typ", $typ);
$stmt->bindParam(":ttl", $ttl);
$stmt->bindParam(":ctt", $ctt);
$stmt->bindParam(":img", $img);
$stmt->execute();
if($stmt){
header("Location: /forum/post/?post=$pid");
}else{
msg("Couldn't submit post. This has been reported for you.");
header("Location: /forum");
}
?>

57
report.css Normal file
View File

@@ -0,0 +1,57 @@
html, body{
height: calc(100% - 1em);
/* Allows the body content be centered vartically.
No idea why the "-1em" part matters, but it does and it works so don't touch it unless you're willing to see the bug through
*/
}
#updateCard{
display: inline-block;
padding: 2em 4em;
margin: 0 auto 10% auto;
text-align: center;
width: 35%;
}
.question{
font-size: 1.1em;
margin-top: 2em;
margin-bottom: 0.7em;
}
/* Something's wrong here */
form>*{
margin-left: auto;
margin-right: auto;
}
#instructions{
width: 90%;
margin: 1em auto;
}
#another{
color: #00d09f;
text-decoration: none;
}
#another:hover{
text-decoration: underline;
}
button[type=submit]{
font-size: 1em;
background-color: white;
color: #00d09f;
border: 1px solid #00d09f;
padding: 0.5em 1em;
margin-top: 2em;
}
h2{
margin-top: 0;
}
textarea{
outline-width: 0;
font-family: inherit;
font-size: 0.9em;
resize: none;
width: 90%;
border: 1px solid #bbb;
border-radius: 0.3em;
padding: 0.3em 0.5em;
color: #333;
font-size: 1em;
}

45
report.php Normal file
View File

@@ -0,0 +1,45 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
?>
<!DOCTYPE html>
<html>
<?php
$css = "report";
include $_SERVER['DOCUMENT_ROOT']."/res/head";
?>
<body>
<?php
include $_SERVER['DOCUMENT_ROOT']."/res/top";
?>
<div id=monoContainer>
<div class='card noHover center'>
<?php
if($_GET["issue"]=="sub"){
$issue = $_POST["issue"];
$reporter = $current_user;
$stmt = $conn->prepare("INSERT INTO issue_tracker (reporter, comment) VALUES (:reporter, :issue)");
$stmt->bindParam(":issue", $issue);
$stmt->bindParam(":reporter", $reporter);
$result = $stmt->execute();
if($stmt){
echo "<h2>Thank You.<br>Your issue has been submitted and will be reviewed shortly.</h2><p>Until it is resolved, please bear in mind that there is only one person who maintains this entire site, and he has the same amount of schoolwork as you do.<br>Thank you for being patient.</p><br><a id=another href='?'>Need to submit another?</a>";
}else{
echo "<h2>There was an issue submitting your issue.</h2><p>I'd tell you to report it, but that doesn't seem to be an option. Instead, please contact Luke Ogburn in person and tell him to fix this.</p>";
}
}else{
echo "
<h2>Report Issue</h2>
<form method=POST action=?issue=sub>
<p id=instructions>Please explain the issue, and include anything you feel might be useful for me to know</p>
<textarea name=issue rows=6 autofocus></textarea>
<button type=submit name=submit>Submit</button>
</form>";
}
?>
</div>
</div>
</body>
</html>

1
res/classes Normal file
View File

@@ -0,0 +1 @@
biology,history,chemistry,english,world_language

16
res/commentSub.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
$pid = $_GET["post"];
$uid = $current_user;
$cmt = $_POST["comment"];
$cmt = encodeUserLink($cmt, $uid, $pid);
$stmt = $conn->prepare("INSERT INTO comments (post_id, poster_id, text) VALUES (:pid, :uid, :cmt)");
$stmt->bindParam(":pid", $pid);
$stmt->bindParam(":uid", $uid);
$stmt->bindParam(":cmt", $cmt);
$result = $stmt->execute();
header("Location: /forum/post/?post=$pid#bottomOfComments");
?>

131
res/comments Normal file
View File

@@ -0,0 +1,131 @@
<?php
//deleting and reporting comments are in the actual post in order to be able to give the affirmative or negative msg on completion or error
$stmt = $conn->prepare("SELECT * FROM comments WHERE post_id = :pid ORDER BY date ASC");
$stmt->bindParam(":pid", $_GET["post"]);
$stmt->execute();
$row = $stmt->fetchAll();
if(isset($_GET["a"])){
conn();
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM alerts WHERE id = :id");
$stmt->bindParam(":id", $_GET["a"]);
$stmt->execute();
$res = $stmt->fetch(PDO::FETCH_OBJ);
if($res->mentionee == $current_user){
alertDelete($_GET["a"]);
}
}
?>
<div class="container card noHover">
<div id=comments>
<div id=commentWriter>
<script>
function getContent(){
document.getElementById("realText").value = document.getElementById("commentEditor").innerHTML;
}
function findPos(obj) {
return obj.getBoundingClientRect().top - obj.clientHeight;
}
function addToCW(text){
document.getElementById("commentEditor").innerHTML = document.getElementById("commentEditor").innerHTML + "@" + text + " ";
document.getElementById("realText").value = document.getElementById("commentEditor").innerHTML;
window.scrollBy(0, findPos(document.getElementById("commentWriter")));
}
</script>
<?php
if(isset($_GET["report"])){
$stmt = $conn->prepare("SELECT * FROM comments WHERE id = :id");
$rid = $_GET["report"];
$stmt->bindParam(":id", $rid);
$stmt->execute();
$comment = $stmt->fetch(PDO::FETCH_OBJ);
$commentID = intval($comment->id);
if($commentID!=""){
$stmt = $conn->prepare("SELECT * FROM comments WHERE id = :id");
$stmt->bindParam(":id", $commentID);
$stmt->execute();
$return = $stmt->fetch(PDO::FETCH_OBJ);
$current = $return->reports;
if(strpos($current, $current_user) === false){
$new = $current.$current_user.",";
$stmt = $conn->prepare("UPDATE comments SET reports = :new WHERE id = :id");
$stmt->bindParam(":new", $new);
$stmt->bindParam(":id", $commentID);
$stmt->execute();
if($stmt){
msg("Comment reported.");
header("Refresh:0");
}else{
msg("Error reporting comment.");
header("Refresh:0");
}
}else{
msg("Your report has already been recorded.");
header("Refresh:0");
}
}
}
if(isset($_GET["reply"])){
$name = getUserInfo($_GET["reply"])->name;
$reply = "&reply=".$_GET["reply"];
$repNotif = "<p style=\"float:left;font-size:1em;margin:0.5em 0.3em;\">(Replying to $name)</p>";
}else{
$reply = $repNotif = "";
}
?>
<form method=POST action=/res/commentSub.php?post=<?=$_GET["post"].$reply; ?>>
<div contentEditable=true id=commentEditor name=commentPsuedo placeholder="Add your ideas" onkeyup=getContent()></div>
<textarea id=realText name=comment style="display:none"></textarea>
<div id=commentWriterButtons>
<?=$repNotif; ?>
<div id=commentSubmitWrapper>
<p id=rulesReminder>Remember: we have <a href="/rules.php" target=_BLANK>rules</a>!</p>
<button id=commentSubmitButton type=submit>SUBMIT</button>
</div>
</div>
</form>
</div>
<!-- submitted comments -->
<div id=submittedComments>
<?php
foreach($row as $comment){
$uname = getUserInfo($comment["poster_id"])->name;
$comment["text"] = decodeUserLink($comment["text"]);
$teacher = getUserInfo($comment["poster_id"])->teacher?"<i class=material-icons>school</i>":"";
if($comment["poster_id"] == $current_user){
$repDel = "<p class=commentReport><a href=?delc=".$comment["id"]."&post=".$_GET['post'].">delete</a></p>";
}else{
$repDel = "<a href=?post=".$_GET['post']."&repc=".$comment["id"]." class=commentReport>report</a>";
}
if($_GET["a"]==$comment['id']){
$a = "current";
echo "<script>document.addEventListener('DOMContentLoaded',function(event) {window.scrollBy(-500,-500);});</script>";
}else{
$a = "";
}
echo "
<div class='comment $a'>
<a name=".$comment['id']."></a>
<div class=commentTop>
<p><a href=/user/?user=".$comment["poster_id"]." class=commentName> ".$uname."</a>".$teacher." <span class=commentTime>".makeDate($comment['date'])."</span></p>
</div>
<div class=commentMiddle>".hyperlink($comment['text'])."</div>
<div class=commentBottom>
".$repDel."
<span class=commentReply onclick=\"addToCW('".$uname."')\">Reply</span>
</div>
</div>";
}
?>
<a name=bottomOfComments></a>
</div>
</div>
</div>

23
res/head Normal file
View File

@@ -0,0 +1,23 @@
<head>
<meta charset=UTF-8>
<title>IB Forum</title>
<link rel=stylesheet type=text/css href=/style.css>
<link rel=stylesheet type=text/css href=/mobile.css>
<?php
if(getUserInfo($current_user)->dark_theme){
echo "<link rel=stylesheet type=text/css href=/darkTheme.css>";
}
?>
<link rel=stylesheet type=text/css href=<?php echo isset($css)?$css:"/unset"; ?>.css>
<link rel=stylesheet type=text/css href=<?php echo isset($css2)?$css2:"/unset"; ?>.css>
<link rel="icon" href="/res/i/favicon.png">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script src="https://apis.google.com/js/platform.js" async defer></script>
<?php
if(getUserInfo($current_user)->snow){
echo "<script src=/res/snowstorm.js></script>";
}
?>
<meta name="google-signin-client_id" content="107876463917-vju8u1c0m5ceu00v92ejim138gae7ktb.apps.googleusercontent.com">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>

BIN
res/i/clip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
res/i/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
res/i/ham.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 B

BIN
res/i/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
res/i/user.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
res/montserrat.ttf Normal file

Binary file not shown.

93
res/notifs Normal file
View File

@@ -0,0 +1,93 @@
<?php
if(isset($_GET["del"])&&verifyUser("admin")){
conn();
$stmt = $conn->prepare("DELETE FROM notices WHERE id = :id");
$stmt->bindParam(":id", $_GET["del"]);
$stmt->execute();
header("Location: /forum");
}
if(isset($_POST["notif"])&&verifyUser("admin")){
conn();
$stmt = $conn->prepare("INSERT INTO notices (text) VALUES (:text)");
$stmt->bindParam(":text", $_POST["notif"]);
$stmt->execute();
unset($_POST["notif"]);
header("Location: /forum");
}
?>
<div id=right>
<div class="card noHover">
<h3 class=notifTitle>NOTIFS</h3>
<p>
<?php
conn();
$stmt = $conn->prepare("SELECT * FROM notices ORDER BY id DESC");
$stmt->execute();
$notices = $stmt->fetchAll();
foreach($notices as $notice){
if(verifyUser("admin")){
$notice = "<p class=notif><a class=deletable href=?del=".$notice['id'].">".$notice["text"]."</a></p>";
}else{
$notice = "<p>".$notice["text"]."</p>";
}
echo $notice;
}
if($notices==NULL){
echo "<i>No notifs.</i>";
}
?>
</p>
</div>
<div class="card noHover">
<h3 class=notifTitle>MENTIONS</h3>
<p>
<?php
conn();
$stmt = $conn->prepare("SELECT * FROM alerts WHERE mentionee = :cu ORDER BY id ASC");
$stmt->bindParam(":cu", $current_user);
$stmt->execute();
$alerts = $stmt->fetchAll();
foreach($alerts as $alert){
echo "<a class=alert href=/forum/post/?a=".$alert['id']."&post=".$alert['post_id']."#".$alert['id'].">".getUserInfo($alert['mentioner'])->name." mentioned you</a>";
}
if($alerts==NULL){
echo "<i>No mentions</i>";
}
?>
</p>
</div>
<?php
if(verifyUser("admin")){
//Reported posts
echo "<div class='card noHover'>
<h3 class=norifTitle>REPORTED POSTS</h3>
";
conn();
$stmt = $conn->prepare("SELECT * FROM forums WHERE reports IS NOT NULL");
$stmt->execute();
$res = $stmt->fetchAll();
foreach($res as $post){
$times = substr_count($post["reports"], ",");
$times = $times==1?"1 time":"$times times";
echo "<p><a class=noStyle href=/admin/portal/reportedPost.php?post=".$post['post_id'].">Post ".$post["post_id"]." has been reported $times</a></p>";
}
if(count($res)==0){
echo "<p><i>Nothing has been reported.</i></p>";
}
echo "</div>";
//Adding notifs
echo"\n<div class='card noHover'>
<h3 class=notifTitle>ADD NOTIFS</h3>
<form method=POST action='' style='width:100%;'>
<input id=notifAdder type=text name=notif placeholder='Press enter to submit' style=color:inherit>
</form>
<br>
<h3 class=notifTitle>DELETE NOTIFS</h3>
<p id=notifAdminMsg>You can delete any notif by clicking on it. Keep in mind that once you click it, it's gone forever. Don't delete something if you aren't sure it should be deleted!<br><br>
Make sure notifs apply to everyone!</p>
</div>";
}
?>
</div>

64
res/randomZone Normal file
View File

@@ -0,0 +1,64 @@
<div class="card noHover">
<h3 class=notifTitle>RANDOM ZONE</h3>
<p>
<?php
$randomArray = [
"You look nice today.",
"You're doing a great job.",
"I hope you're having a good day! You deserve it.",
"Your friends are all rooting for you.",
"Ever noticed that the search bar's words change?",
"I bet giraffes' coffee is cold by the time it gets to its stomach.",
"I saw some guy walking around with a duck the other day.",
"This site is user-based; make sure you contribute!",
"Ever considered buying a boat?",
"We should all go ice-skating over winter break, that would be fun.",
"Remember to take a breath every once in a while.",
"School isn't everything. Take care of yourself.",
"The surface area of an average-sized brick is 79 cm squared.",
"Despite what Mrs. Trickett says, the mitochondria IS the powerhouse of the cell.",
"ATLEE stands for All Trees Like Eating Eggs.",
"I heard that someone has a crush on ".str_replace(str_split(-_), " ", getUserInfo($current_user)->name),
"Left handed people tend to be more artistic.",
"I hope you're not going to leave this site... that literally kills me, you know.",
"Ctrl (or cmd on Mac) + Shift + T reopens your last closed tab.",
"Aliens probably don't go to school.",
"^-^",
"Edelman has a Keurig you can use.",
"Does Santa know when I procrastinate?",
"You're in a coma.<br>We're trying a new technique to get to you.<br>Please wake up.<br>We miss you.",
"The patent for toilet paper shows it going over, not under.",
"Luke Ogburn carries mints in his backpack. Just ask and he'll give you one!",
"Someone ate my pringes :(",
"What if time goes backwards, but we just don't notice because our memories rewind too.",
"You seem like a nice person.",
"The school's layout is based off of that of a prison's.",
"Text someone you like and tell them why you like them. They'll appreciate it.",
"Rice isn't that hard to cook.",
"I wonder if there are any secret passages in the school.",
"Pineapples have neither pines nor apples in them.",
"Fear is information, don't ignore it.",
"If you're hungry, then eat.",
"If you're thirsty, then drink",
"Give yourself time. Butterflies don't form in a day.",
"Ask yourself: What would make me happy today?",
"Beauty shouldn't be pain. Being comfortable will make you happy, which will make you beautiful.",
"The more people use this site, the better it becomes.",
"Onions don't cry when they chop humans.",
"Never trust a plastic hippo.",
"Tabs are just capital spaces.",
"The very existence of socks is proof that shoes don't work.",
"Humans are the only creatures who care about time. Maybe it doesn't matter as much as we think it does.",
"People like you.",
"Chicken is better than turkey and you can't change my mind.",
"You look great today.",
"People are happy when you're happy, because they like you and want you to succeed in life.",
"In dog years, humans regularly live to 800+ years old. They probably think we're immortal or something.",
"If tipping were illegal, wait staff would be paid more and wouldn't neet tips in the first place.",
"I, for one, think that you're a good person."
];
$randomArray = array_filter($randomArray);
echo $randomArray[mt_rand(0, sizeof($randomArray)-1)];
?>
</p>
</div>

BIN
res/roboto.ttf Normal file

Binary file not shown.

7
res/rules Normal file
View File

@@ -0,0 +1,7 @@
<ul>
<li>Don't hurt anyone</li>
<li>Any cheating will be reported</li>
<li>Cyber bullying is still illegal</li>
<li>Be hum</li>
<li>Remember anyone can see your post</li>
<li>Just be sensible</li>

666
res/snowstorm.js Normal file
View File

@@ -0,0 +1,666 @@
/** @license
* DHTML Snowstorm! JavaScript-based snow for web pages
* Making it snow on the internets since 2003. You're welcome.
* -----------------------------------------------------------
* Version 1.44.20131208 (Previous rev: 1.44.20131125)
* Copyright (c) 2007, Scott Schiller. All rights reserved.
* Code provided under the BSD License
* http://schillmania.com/projects/snowstorm/license.txt
*/
/*jslint nomen: true, plusplus: true, sloppy: true, vars: true, white: true */
/*global window, document, navigator, clearInterval, setInterval */
var snowStorm = (function(window, document) {
// --- common properties ---
this.autoStart = true; // Whether the snow should start automatically or not.
this.excludeMobile = true; // Snow is likely to be bad news for mobile phones' CPUs (and batteries.) Enable at your own risk.
this.flakesMax = 128; // Limit total amount of snow made (falling + sticking)
this.flakesMaxActive = 64; // Limit amount of snow falling at once (less = lower CPU use)
this.animationInterval = 33; // Theoretical "miliseconds per frame" measurement. 20 = fast + smooth, but high CPU use. 50 = more conservative, but slower
this.useGPU = true; // Enable transform-based hardware acceleration, reduce CPU load.
this.className = null; // CSS class name for further customization on snow elements
this.excludeMobile = true; // Snow is likely to be bad news for mobile phones' CPUs (and batteries.) By default, be nice.
this.flakeBottom = null; // Integer for Y axis snow limit, 0 or null for "full-screen" snow effect
this.followMouse = false; // Snow movement can respond to the user's mouse
this.snowColor = '#aaf'; // Don't eat (or use?) yellow snow.
this.snowCharacter = '&bull;'; // &bull; = bullet, &middot; is square on some systems etc.
this.snowStick = true; // Whether or not snow should "stick" at the bottom. When off, will never collect.
this.targetElement = null; // element which snow will be appended to (null = document.body) - can be an element ID eg. 'myDiv', or a DOM node reference
this.useMeltEffect = true; // When recycling fallen snow (or rarely, when falling), have it "melt" and fade out if browser supports it
this.useTwinkleEffect = false; // Allow snow to randomly "flicker" in and out of view while falling
this.usePositionFixed = true; // true = snow does not shift vertically when scrolling. May increase CPU load, disabled by default - if enabled, used only where supported
this.usePixelPosition = false; // Whether to use pixel values for snow top/left vs. percentages. Auto-enabled if body is position:relative or targetElement is specified.
// --- less-used bits ---
this.freezeOnBlur = true; // Only snow when the window is in focus (foreground.) Saves CPU.
this.flakeLeftOffset = 0; // Left margin/gutter space on edge of container (eg. browser window.) Bump up these values if seeing horizontal scrollbars.
this.flakeRightOffset = 0; // Right margin/gutter space on edge of container
this.flakeWidth = 8; // Max pixel width reserved for snow element
this.flakeHeight = 8; // Max pixel height reserved for snow element
this.vMaxX = 3; // Maximum X velocity range for snow
this.vMaxY = 3; // Maximum Y velocity range for snow
this.zIndex = -1; // CSS stacking order applied to each snowflake
// --- "No user-serviceable parts inside" past this point, yadda yadda ---
var storm = this,
features,
// UA sniffing and backCompat rendering mode checks for fixed position, etc.
isIE = navigator.userAgent.match(/msie/i),
isIE6 = navigator.userAgent.match(/msie 6/i),
isMobile = navigator.userAgent.match(/mobile|opera m(ob|in)/i),
isBackCompatIE = (isIE && document.compatMode === 'BackCompat'),
noFixed = (isBackCompatIE || isIE6),
screenX = null, screenX2 = null, screenY = null, scrollY = null, docHeight = null, vRndX = null, vRndY = null,
windOffset = 1,
windMultiplier = 1, //used to be 2
flakeTypes = 6,
fixedForEverything = false,
targetElementIsRelative = false,
opacitySupported = (function(){
try {
document.createElement('div').style.opacity = '0.9';
} catch(e) {
return false;
}
return true;
}()),
didInit = false,
docFrag = document.createDocumentFragment();
features = (function() {
var getAnimationFrame;
/**
* hat tip: paul irish
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/
* https://gist.github.com/838785
*/
function timeoutShim(callback) {
window.setTimeout(callback, 1000/(storm.animationInterval || 20));
}
var _animationFrame = (window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
timeoutShim);
// apply to window, avoid "illegal invocation" errors in Chrome
getAnimationFrame = _animationFrame ? function() {
return _animationFrame.apply(window, arguments);
} : null;
var testDiv;
testDiv = document.createElement('div');
function has(prop) {
// test for feature support
var result = testDiv.style[prop];
return (result !== undefined ? prop : null);
}
// note local scope.
var localFeatures = {
transform: {
ie: has('-ms-transform'),
moz: has('MozTransform'),
opera: has('OTransform'),
webkit: has('webkitTransform'),
w3: has('transform'),
prop: null // the normalized property value
},
getAnimationFrame: getAnimationFrame
};
localFeatures.transform.prop = (
localFeatures.transform.w3 ||
localFeatures.transform.moz ||
localFeatures.transform.webkit ||
localFeatures.transform.ie ||
localFeatures.transform.opera
);
testDiv = null;
return localFeatures;
}());
this.timer = null;
this.flakes = [];
this.disabled = false;
this.active = false;
this.meltFrameCount = 20;
this.meltFrames = [];
this.setXY = function(o, x, y) {
if (!o) {
return false;
}
if (storm.usePixelPosition || targetElementIsRelative) {
o.style.left = (x - storm.flakeWidth) + 'px';
o.style.top = (y - storm.flakeHeight) + 'px';
} else if (noFixed) {
o.style.right = (100-(x/screenX*100)) + '%';
// avoid creating vertical scrollbars
o.style.top = (Math.min(y, docHeight-storm.flakeHeight)) + 'px';
} else {
if (!storm.flakeBottom) {
// if not using a fixed bottom coordinate...
o.style.right = (100-(x/screenX*100)) + '%';
o.style.bottom = (100-(y/screenY*100)) + '%';
} else {
// absolute top.
o.style.right = (100-(x/screenX*100)) + '%';
o.style.top = (Math.min(y, docHeight-storm.flakeHeight)) + 'px';
}
}
};
this.events = (function() {
var old = (!window.addEventListener && window.attachEvent), slice = Array.prototype.slice,
evt = {
add: (old?'attachEvent':'addEventListener'),
remove: (old?'detachEvent':'removeEventListener')
};
function getArgs(oArgs) {
var args = slice.call(oArgs), len = args.length;
if (old) {
args[1] = 'on' + args[1]; // prefix
if (len > 3) {
args.pop(); // no capture
}
} else if (len === 3) {
args.push(false);
}
return args;
}
function apply(args, sType) {
var element = args.shift(),
method = [evt[sType]];
if (old) {
element[method](args[0], args[1]);
} else {
element[method].apply(element, args);
}
}
function addEvent() {
apply(getArgs(arguments), 'add');
}
function removeEvent() {
apply(getArgs(arguments), 'remove');
}
return {
add: addEvent,
remove: removeEvent
};
}());
function rnd(n,min) {
if (isNaN(min)) {
min = 0;
}
return (Math.random()*n)+min;
}
function plusMinus(n) {
return (parseInt(rnd(2),10)===1?n*-1:n);
}
this.randomizeWind = function() {
var i;
vRndX = plusMinus(rnd(storm.vMaxX,0.2));
vRndY = rnd(storm.vMaxY,0.2);
if (this.flakes) {
for (i=0; i<this.flakes.length; i++) {
if (this.flakes[i].active) {
this.flakes[i].setVelocities();
}
}
}
};
this.scrollHandler = function() {
var i;
// "attach" snowflakes to bottom of window if no absolute bottom value was given
scrollY = (storm.flakeBottom ? 0 : parseInt(window.scrollY || document.documentElement.scrollTop || (noFixed ? document.body.scrollTop : 0), 10));
if (isNaN(scrollY)) {
scrollY = 0; // Netscape 6 scroll fix
}
if (!fixedForEverything && !storm.flakeBottom && storm.flakes) {
for (i=0; i<storm.flakes.length; i++) {
if (storm.flakes[i].active === 0) {
storm.flakes[i].stick();
}
}
}
};
this.resizeHandler = function() {
if (window.innerWidth || window.innerHeight) {
screenX = window.innerWidth - 16 - storm.flakeRightOffset;
screenY = (storm.flakeBottom || window.innerHeight);
} else {
screenX = (document.documentElement.clientWidth || document.body.clientWidth || document.body.scrollWidth) - (!isIE ? 8 : 0) - storm.flakeRightOffset;
screenY = storm.flakeBottom || document.documentElement.clientHeight || document.body.clientHeight || document.body.scrollHeight;
}
docHeight = document.body.offsetHeight;
screenX2 = parseInt(screenX/2,10);
};
this.resizeHandlerAlt = function() {
screenX = storm.targetElement.offsetWidth - storm.flakeRightOffset;
screenY = storm.flakeBottom || storm.targetElement.offsetHeight;
screenX2 = parseInt(screenX/2,10);
docHeight = document.body.offsetHeight;
};
this.freeze = function() {
// pause animation
if (!storm.disabled) {
storm.disabled = 1;
} else {
return false;
}
storm.timer = null;
};
this.resume = function() {
if (storm.disabled) {
storm.disabled = 0;
} else {
return false;
}
storm.timerInit();
};
this.toggleSnow = function() {
if (!storm.flakes.length) {
// first run
storm.start();
} else {
storm.active = !storm.active;
if (storm.active) {
storm.show();
storm.resume();
} else {
storm.stop();
storm.freeze();
}
}
};
this.stop = function() {
var i;
this.freeze();
for (i=0; i<this.flakes.length; i++) {
this.flakes[i].o.style.display = 'none';
}
storm.events.remove(window,'scroll',storm.scrollHandler);
storm.events.remove(window,'resize',storm.resizeHandler);
if (storm.freezeOnBlur) {
if (isIE) {
storm.events.remove(document,'focusout',storm.freeze);
storm.events.remove(document,'focusin',storm.resume);
} else {
storm.events.remove(window,'blur',storm.freeze);
storm.events.remove(window,'focus',storm.resume);
}
}
};
this.show = function() {
var i;
for (i=0; i<this.flakes.length; i++) {
this.flakes[i].o.style.display = 'block';
}
};
this.SnowFlake = function(type,x,y) {
var s = this;
this.type = type;
this.x = x||parseInt(rnd(screenX-20),10);
this.y = (!isNaN(y)?y:-rnd(screenY)-12);
this.vX = null;
this.vY = null;
this.vAmpTypes = [1,1.2,1.4,1.6,1.8]; // "amplification" for vX/vY (based on flake size/type)
this.vAmp = this.vAmpTypes[this.type] || 1;
this.melting = false;
this.meltFrameCount = storm.meltFrameCount;
this.meltFrames = storm.meltFrames;
this.meltFrame = 0;
this.twinkleFrame = 0;
this.active = 1;
this.fontSize = (10+(this.type/5)*10);
this.o = document.createElement('div');
this.o.innerHTML = storm.snowCharacter;
if (storm.className) {
this.o.setAttribute('class', storm.className);
}
this.o.style.color = storm.snowColor;
this.o.style.position = (fixedForEverything?'fixed':'absolute');
if (storm.useGPU && features.transform.prop) {
// GPU-accelerated snow.
this.o.style[features.transform.prop] = 'translate3d(0px, 0px, 0px)';
}
this.o.style.width = storm.flakeWidth+'px';
this.o.style.height = storm.flakeHeight+'px';
this.o.style.fontFamily = 'arial,verdana';
this.o.style.cursor = 'default';
this.o.style.overflow = 'hidden';
this.o.style.fontWeight = 'normal';
this.o.style.zIndex = storm.zIndex;
docFrag.appendChild(this.o);
this.refresh = function() {
if (isNaN(s.x) || isNaN(s.y)) {
// safety check
return false;
}
storm.setXY(s.o, s.x, s.y);
};
this.stick = function() {
if (noFixed || (storm.targetElement !== document.documentElement && storm.targetElement !== document.body)) {
s.o.style.top = (screenY+scrollY-storm.flakeHeight)+'px';
} else if (storm.flakeBottom) {
s.o.style.top = storm.flakeBottom+'px';
} else {
s.o.style.display = 'none';
s.o.style.bottom = '0%';
s.o.style.position = 'fixed';
s.o.style.display = 'block';
}
};
this.vCheck = function() {
if (s.vX>=0 && s.vX<0.2) {
s.vX = 0.2;
} else if (s.vX<0 && s.vX>-0.2) {
s.vX = -0.2;
}
if (s.vY>=0 && s.vY<0.2) {
s.vY = 0.2;
}
};
this.move = function() {
var vX = s.vX*windOffset, yDiff;
s.x += vX;
s.y += (s.vY*s.vAmp);
if (s.x >= screenX || screenX-s.x < storm.flakeWidth) { // X-axis scroll check
s.x = 0;
} else if (vX < 0 && s.x-storm.flakeLeftOffset < -storm.flakeWidth) {
s.x = screenX-storm.flakeWidth-1; // flakeWidth;
}
s.refresh();
yDiff = screenY+scrollY-s.y+storm.flakeHeight;
if (yDiff<storm.flakeHeight) {
s.active = 0;
if (storm.snowStick) {
s.stick();
} else {
s.recycle();
}
} else {
if (storm.useMeltEffect && s.active && s.type < 3 && !s.melting && Math.random()>0.998) {
// ~1/1000 chance of melting mid-air, with each frame
s.melting = true;
s.melt();
// only incrementally melt one frame
// s.melting = false;
}
if (storm.useTwinkleEffect) {
if (s.twinkleFrame < 0) {
if (Math.random() > 0.97) {
s.twinkleFrame = parseInt(Math.random() * 8, 10);
}
} else {
s.twinkleFrame--;
if (!opacitySupported) {
s.o.style.visibility = (s.twinkleFrame && s.twinkleFrame % 2 === 0 ? 'hidden' : 'visible');
} else {
s.o.style.opacity = (s.twinkleFrame && s.twinkleFrame % 2 === 0 ? 0 : 1);
}
}
}
}
};
this.animate = function() {
// main animation loop
// move, check status, die etc.
s.move();
};
this.setVelocities = function() {
s.vX = vRndX+rnd(storm.vMaxX*0.12,0.1);
s.vY = vRndY+rnd(storm.vMaxY*0.12,0.1);
};
this.setOpacity = function(o,opacity) {
if (!opacitySupported) {
return false;
}
o.style.opacity = opacity;
};
this.melt = function() {
if (!storm.useMeltEffect || !s.melting) {
s.recycle();
} else {
if (s.meltFrame < s.meltFrameCount) {
s.setOpacity(s.o,s.meltFrames[s.meltFrame]);
s.o.style.fontSize = s.fontSize-(s.fontSize*(s.meltFrame/s.meltFrameCount))+'px';
s.o.style.lineHeight = storm.flakeHeight+2+(storm.flakeHeight*0.75*(s.meltFrame/s.meltFrameCount))+'px';
s.meltFrame++;
} else {
s.recycle();
}
}
};
this.recycle = function() {
s.o.style.display = 'none';
s.o.style.position = (fixedForEverything?'fixed':'absolute');
s.o.style.bottom = 'auto';
s.setVelocities();
s.vCheck();
s.meltFrame = 0;
s.melting = false;
s.setOpacity(s.o,1);
s.o.style.padding = '0px';
s.o.style.margin = '0px';
s.o.style.fontSize = s.fontSize+'px';
s.o.style.lineHeight = (storm.flakeHeight+2)+'px';
s.o.style.textAlign = 'center';
s.o.style.verticalAlign = 'baseline';
s.x = parseInt(rnd(screenX-storm.flakeWidth-20),10);
s.y = parseInt(rnd(screenY)*-1,10)-storm.flakeHeight;
s.refresh();
s.o.style.display = 'block';
s.active = 1;
};
this.recycle(); // set up x/y coords etc.
this.refresh();
};
this.snow = function() {
var active = 0, flake = null, i, j;
for (i=0, j=storm.flakes.length; i<j; i++) {
if (storm.flakes[i].active === 1) {
storm.flakes[i].move();
active++;
}
if (storm.flakes[i].melting) {
storm.flakes[i].melt();
}
}
if (active<storm.flakesMaxActive) {
flake = storm.flakes[parseInt(rnd(storm.flakes.length),10)];
if (flake.active === 0) {
flake.melting = true;
}
}
if (storm.timer) {
features.getAnimationFrame(storm.snow);
}
};
this.mouseMove = function(e) {
if (!storm.followMouse) {
return true;
}
var x = parseInt(e.clientX,10);
if (x<screenX2) {
windOffset = -windMultiplier+(x/screenX2*windMultiplier);
} else {
x -= screenX2;
windOffset = (x/screenX2)*windMultiplier;
}
};
this.createSnow = function(limit,allowInactive) {
var i;
for (i=0; i<limit; i++) {
storm.flakes[storm.flakes.length] = new storm.SnowFlake(parseInt(rnd(flakeTypes),10));
if (allowInactive || i>storm.flakesMaxActive) {
storm.flakes[storm.flakes.length-1].active = -1;
}
}
storm.targetElement.appendChild(docFrag);
};
this.timerInit = function() {
storm.timer = true;
storm.snow();
};
this.init = function() {
var i;
for (i=0; i<storm.meltFrameCount; i++) {
storm.meltFrames.push(1-(i/storm.meltFrameCount));
}
storm.randomizeWind();
storm.createSnow(storm.flakesMax); // create initial batch
storm.events.add(window,'resize',storm.resizeHandler);
storm.events.add(window,'scroll',storm.scrollHandler);
if (storm.freezeOnBlur) {
if (isIE) {
storm.events.add(document,'focusout',storm.freeze);
storm.events.add(document,'focusin',storm.resume);
} else {
storm.events.add(window,'blur',storm.freeze);
storm.events.add(window,'focus',storm.resume);
}
}
storm.resizeHandler();
storm.scrollHandler();
if (storm.followMouse) {
storm.events.add(isIE?document:window,'mousemove',storm.mouseMove);
}
storm.animationInterval = Math.max(20,storm.animationInterval);
storm.timerInit();
};
this.start = function(bFromOnLoad) {
if (!didInit) {
didInit = true;
} else if (bFromOnLoad) {
// already loaded and running
return true;
}
if (typeof storm.targetElement === 'string') {
var targetID = storm.targetElement;
storm.targetElement = document.getElementById(targetID);
if (!storm.targetElement) {
throw new Error('Snowstorm: Unable to get targetElement "'+targetID+'"');
}
}
if (!storm.targetElement) {
storm.targetElement = (document.body || document.documentElement);
}
if (storm.targetElement !== document.documentElement && storm.targetElement !== document.body) {
// re-map handler to get element instead of screen dimensions
storm.resizeHandler = storm.resizeHandlerAlt;
//and force-enable pixel positioning
storm.usePixelPosition = true;
}
storm.resizeHandler(); // get bounding box elements
storm.usePositionFixed = (storm.usePositionFixed && !noFixed && !storm.flakeBottom); // whether or not position:fixed is to be used
if (window.getComputedStyle) {
// attempt to determine if body or user-specified snow parent element is relatlively-positioned.
try {
targetElementIsRelative = (window.getComputedStyle(storm.targetElement, null).getPropertyValue('position') === 'relative');
} catch(e) {
// oh well
targetElementIsRelative = false;
}
}
fixedForEverything = storm.usePositionFixed;
if (screenX && screenY && !storm.disabled) {
storm.init();
storm.active = true;
}
};
function doDelayedStart() {
window.setTimeout(function() {
storm.start(true);
}, 20);
// event cleanup
storm.events.remove(isIE?document:window,'mousemove',doDelayedStart);
}
function doStart() {
if (!storm.excludeMobile || !isMobile) {
doDelayedStart();
}
// event cleanup
storm.events.remove(window, 'load', doStart);
}
// hooks for starting the snow
if (storm.autoStart) {
storm.events.add(window, 'load', doStart, false);
}
return this;
}(window, document));

21
res/toggleDarkTheme.php Normal file
View File

@@ -0,0 +1,21 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
if(getUserInfo($current_user)->dark_theme){
$stmt = $conn->prepare("UPDATE users SET dark_theme = 0 WHERE id = :usr");
$stmt->bindParam(":usr", $current_user);
$stmt->execute();
}else{
$stmt = $conn->prepare("UPDATE users SET dark_theme = 1 WHERE id = :usr");
$stmt->bindParam(":usr", $current_user);
$stmt->execute();
}
if($stmt){
msg("Theme updated.");
}else{
msg("Error updating theme.");
}
header("Location: /user/settings.php");
?>

21
res/toggleSnow.php Normal file
View File

@@ -0,0 +1,21 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
if(getUserInfo($current_user)->snow){
$stmt = $conn->prepare("UPDATE users SET snow = 0 WHERE id = :usr");
$stmt->bindParam(":usr", $current_user);
$stmt->execute();
}else{
$stmt = $conn->prepare("UPDATE users SET snow = 1 WHERE id = :usr");
$stmt->bindParam(":usr", $current_user);
$stmt->execute();
}
if($stmt){
msg("Snow setting changed.");
}else{
msg("Error changing snow.");
}
header("Location: /user/settings.php");
?>

49
res/top Normal file
View File

@@ -0,0 +1,49 @@
<?php
$searchArrayMobile = ["Search", "Looking for something?", "Hey, a search bar!"];
$searchArray = ["You can search all posts and questions here", "Looking for something specific?", "Type 'history:' before your search to narrow it down to one class", "Looking for something?", "Search for what you need", "Oh look, there's a search bar", "Don't do a search now, I'm sleeping (zzz)"];
$searchPlaceholder = "\"".$searchArray[array_rand($searchArray)]."\"";
$searchPlaceholderMobile = "\"".$searchArrayMobile[array_rand($searchArrayMobile)]."\"";
?>
<div id=topSpacer></div>
<div id=top>
<a id=logoLink href="/"><img id=logo src="/res/i/logo.png"></a>
<div id=search>
<form id=searchForm method=GET action=/search>
<input placeholder=<?=$searchPlaceholder?> id=searchBar type=text autocomplete=off name=q value=<?=isset($_GET["q"])?"\"".htmlspecialchars($_GET["q"])."\"":"";?>>
</form>
</div>
<div id=addPost class=noSelect><a href="/post">+ Post</a></div>
<a id=accountWrapper href=<?php echo $verified?"/user/?user=".$current_user:"/user/login.php"; ?>>
<img id=account src=<?php echo $verified?getUserInfo($current_user)->image_url:"/res/i/user.png"; ?>>
</a>
</div>
<!-- Mobile -->
<input id=hamCheck type=checkbox style=display:none>
<div id=topMobile class=mobile>
<div id=mobileMenu><label for=hamCheck><img class=hamburger src=/res/i/ham.png></label></div>
<a id=logoLinkMobile href="/"><img id=logoMobile src="/res/i/logo.png"></a>
<div id=topMobileSpacer></div>
</div>
<div id=leftMobile class='mobile keepRight'>
<label for=hamCheck><img id=hamburgerInLeft class=hamburger src=/res/i/ham.png></label>
<a id=accountWrapperMobile class=noStyle href=<?php echo $verified?"/user/?user=".$current_user:"/user/login.php"; ?>>
<img id=accountMobile src=<?php echo $verified?getUserInfo($current_user)->image_url:"/res/i/user.png"; ?>>
<h2><?=getUserInfo($current_user)->name?></h2>
</a>
<div id=searchMobile>
<form id=searchFormMobile method=GET action=/search>
<input placeholder=<?=$searchPlaceholderMobile?> id=searchBarMobile type=text autocomplete=off name=q value=<?=isset($_GET["q"])?"\"".htmlspecialchars($_GET["q"])."\"":"";?>>
</form>
</div>
<div id=addPostMobile class=noSelect><a href="/post">+ Post</a></div>
<?php include $_SERVER['DOCUMENT_ROOT']."/res/notifs"; ?>
</div>
<?php
if($msg != NULL){
echo "<msg class=neutral>".$msg."</msg>";
}
?>

36
rules.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
if(isset($_POST["submit"]) && verifyUser("admin")){
$txt = "\n<li>".$_POST["rule"]."</li>";
file_put_contents('res/rules', $txt.PHP_EOL , FILE_APPEND | LOCK_EX);
unset($_POST);
}
?>
<!DOCTYPE html>
<html>
<?php include "res/head"; ?>
<body>
<?php
include "res/top";
?>
<div id=monoContainer>
<div class='card noHover'>
<h2 class=center>RULES</h2>
<?php require("res/rules"); ?>
</div>
<?php
if(verifyUser("admin")){
echo "<div class='card noHover center'>
<form action='' method=POST>
<h2>ADD A RULE</h2>
<p><i>Keep in mind that you won't be able to delete this</i></p>
<input type=text name=rule placeholder='Rule to add'>
<button type=submit name=submit>Add</button>
</form>
<br>
</div>";
}
?>
</div>
</body>
</html>

125
search/index.php Normal file
View File

@@ -0,0 +1,125 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
?>
<!DOCTYPE html>
<html>
<?php
$css = "search";
require $_SERVER['DOCUMENT_ROOT']."/res/head";
?>
<body>
<?php
include $_SERVER['DOCUMENT_ROOT']."/res/top";
?>
<div id=results>
<?php
//Setting number of results per page
$GLOBALS["limit"] = 20;
$GLOBALS["page"] = is_numeric($_GET["page"])&&$_GET["page"]>0?$_GET["page"]:1;
$GLOBALS["check"] = $limit * ($page - 1);
function search($statement, $searchByClass){
$limit = $GLOBALS["limit"] + 1;
$page = $GLOBALS["page"];
$start = ($limit - 1) * ($page - 1);
//$limit is set one higher to check if there will be a next page, but is subtracted in the $start math because the math relies on the limit.
if($searchByClass == false){
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM forums WHERE (title LIKE CONCAT('%', :search, '%')) OR (content LIKE CONCAT('%', :search, '%')) ORDER BY date DESC LIMIT $start,$limit");
}else{
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM forums WHERE (title LIKE CONCAT('%', :search, '%') AND section = :section) OR (content LIKE CONCAT('%', :search, '%') AND section = :section) ORDER BY date DESC LIMIT $start,$limit");
$stmt->bindParam(":section", $searchByClass);
}
$stmt->bindParam(":search", $statement);
$stmt->execute();
return $stmt->fetchAll();
}
function searchClassOnly($searchByClass){
$limit = $GLOBALS["limit"] + 1;
$page = $GLOBALS["page"];
$start = ($limit - 1) * ($page - 1);
//The above was just copied from function search()
//If the user looks up something like "chemistry:", there will be no results so might as well give them ALL of the chemistry posts
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM forums WHERE section = :section ORDER BY date DESC LIMIT $start,$limit");
$stmt->bindParam(":section", $searchByClass);
$stmt->execute();
return $stmt->fetchAll();
}
//Setting the array for storing posts' ID, used to make sure results only turn up once. Also initializing the counter for amount of posts
$resArray = array();
$count = 0;
//Getting class specification, returning false if none
preg_match_all("#([A-Za-z]+)(?=:)#", strtok($_GET["q"], " "), $matches);
$class = strtolower($matches[0][0]);
$classes = file_get_contents($_SERVER['DOCUMENT_ROOT']."/res/classes");
$classes = array_filter(explode(",", $classes));
if(in_array($class, $classes)){
$searchByClass = $class;
}else{
$searchByClass = false;
}
//Getting more exact results by searching for strict phrase
foreach(search($search, $searchByClass) as $post){
$resArray[] = $post["post_id"];
}
//Getting more general results by searching for each word indevidually
$noSpaces = preg_replace('/\s+/', ' ', $_GET["q"]." ");
//Adding the space to the GET[q] solves the issue where searching nothing in a class (e.g. "history:") didn't turn up results
$search = $searchByClass==false?$noSpaces:substr($noSpaces, strpos($noSpaces, ":")+1);
$search = explode(" ", strtolower($search));
$exclude = explode("\n", file_get_contents("stopwords.txt"));
$search = array_diff($search, $exclude);
//gets rid of superflous stop words in search
foreach(array_filter($search) as $word){
foreach(search($word." ", $searchByClass) as $post){
$resArray[] = $post["post_id"];
}
foreach(search(" ".$word, $searchByClass) as $post){
$resArray[] = $post["post_id"];
}
}
if(count(array_filter($search)) == 0 && $searchByClass != false){
foreach(searchClassOnly($searchByClass) as $post){
$resArray[] = $post["post_id"];
}
}
$resArray = array_unique($resArray);
foreach($resArray as $post){
$count++;
}
echo "<h2 id=summary>";
if($count==1){
echo "There was 1 result";
}else if($count > $GLOBALS["limit"] || $GLOBALS["page"] > 1){
echo "There were lots of results";
}else{
echo "There were $count results";
}
echo "</h2>";
foreach($resArray as $post){
makePost(getPostInfo($post));
}
$resArray = array_slice($resArray, 0, $GLOBALS["limit"]);
$page = $GLOBALS["page"];
$query = urlencode($_GET["q"]);
echo "<div id=pages>";
echo $page!=1?"<div id=prevPage><a href=/search/?q=$query&page=".($page-1).">&larr;</a></div>":"<div></div>";
echo $count>$GLOBALS["limit"]?"<div id=nextPage><a href=/search/?q=$query&page=".($page+1).">&rarr;</a></div>":"<div></div>";
echo "</div>";
?>
</div>
</body>
</html>

4
search/search.css Normal file
View File

@@ -0,0 +1,4 @@
#results{
width: 60%;
margin: 5% auto;
}

174
search/stopwords.txt Normal file
View File

@@ -0,0 +1,174 @@
a
about
above
after
again
against
all
am
an
and
any
are
aren't
as
at
be
because
been
before
being
below
between
both
but
by
can't
cannot
could
couldn't
did
didn't
do
does
doesn't
doing
don't
down
during
each
few
for
from
further
had
hadn't
has
hasn't
have
haven't
having
he
he'd
he'll
he's
her
here
here's
hers
herself
him
himself
his
how
how's
i
i'd
i'll
i'm
i've
if
in
into
is
isn't
it
it's
its
itself
let's
me
more
most
mustn't
my
myself
no
nor
not
of
off
on
once
only
or
other
ought
our
ours
ourselves
out
over
own
same
shan't
she
she'd
she'll
she's
should
shouldn't
so
some
such
than
that
that's
the
their
theirs
them
themselves
then
there
there's
these
they
they'd
they'll
they're
they've
this
those
through
to
too
under
until
up
very
was
wasn't
we
we'd
we'll
we're
we've
were
weren't
what
what's
when
when's
where
where's
which
while
who
who's
whom
why
why's
with
won't
would
wouldn't
you
you'd
you'll
you're
you've
your
yours
yourself
yourselves

403
style.css Normal file
View File

@@ -0,0 +1,403 @@
/* ------------- Site-wide Rules ------------- */
@font-face{
font-family: Roboto;
src: url('res/roboto.ttf');
}
@font-face{
font-family: Montserrat;
src: url('res/montserrat.ttf');
}
body{
margin: 0;
font-family: 'Roboto', sans-serif;
background-color: #f0f0f0;
}
html{
font-size: 100%;
}
h1, h2, h3, h4, h5, h6{
font-family: 'Montserrat', sans-serif;
}
h2{
font-size: 1.4em;
}
input, button{
outline-width: 0;
}
span[onclick]:hover{
cursor: pointer;
text-decoration: underline;
}
a.color{
color: #00bc8f;
text-decoration: none;
}
a.color:hover{
text-decoration: underline;
}
.noSelect, .tags{
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome and Opera */
}
.card{
color: #333;
background-color: white;
margin-bottom: 2em;
border-radius: 0.2em;
padding: 1em;
}
.card.noMargin{
margin-bottom: 0;
}
.card:not(.noShadow){
box-shadow: 1px 1px 3px #ddd;
}
.card:hover:not(.noShadow):not(.noHover){
box-shadow: 1px 2px 3px #bbb;
}
.postReport{
font-size: 0.8em;
float: left;
}
.postReport>a{
text-decoration: none;
color: #888;
}
.postReport>a:hover{
text-decoration: underline;
}
.center{
text-align: center;
}
.noStyle{
color: inherit;
text-decoration: none;
}
.noStyle:hover{
text-decoration: underline;
}
.smallWidth{
width: 70%;
margin-left: auto;
margin-right: auto;
}
button[type="submit"]:not(#commentSubmitButton){
font-size: 1em;
color: #00d09f;
border: 1px solid #00d09f;
border-radius: 0.2em;
background-color: white;
padding: 0.5em 1em;
margin: 2em auto 0 auto;
display: block;
}
button[type="submit"]:hover{
cursor: pointer;
}
/* ------------- Global forums ------------- */
#container{
width: 80%;
margin: 3% auto;
display: grid;
grid-template-columns: 3fr 1fr;
grid-column-gap: 3%;
}
#container>*{
border-radius: 0.3em;
}
#monoContainer{
width: 45%;
margin: 3% auto;
max-height: 80vh;
}
#monoContainer>*{
border-radius: 0.3em;
}
p[onclick]:hover, span[onclick]:hover, button:hover{
cursor: pointer;
}
.commentTop>p>.material-icons{
font-size: 0.9em !important;
}
/* General forum stuff */
.forumLink{
text-decoration: none;
}
/* ------------- Posts ------------- */
/* Title, username, time posted */
.title>h2{
margin: 0.3em 0 0.4em 0;
}
.preview>p{
margin: 0.3em 0;
}
.info>*{
font-size: 0.75em;
color: #888;
margin: 0;
display: inline-block;
}
.userlink:hover, .postType:hover{
text-decoration: underline;
}
.postType{
color: #666;
font-weight: bold;
margin: 0 0.5em 0 0.2em;
}
.forum{
overflow: hidden;
}
/* Text, clip, image of post previews */
.postPrevImg.clip{
width: 0.67em;
margin-bottom: 0.08em;
margin-left: 0.3em;
display: inline;
}
.forum.image{
display: grid;
grid-template-columns: 3fr 1fr;
grid-column-gap: 1em;
}
.postPrevImg{
width: 100%;
min-height: 100%;
max-height: 100%;
object-fit: cover;
}
/* Back/next buttons at bottom of forum page */
#pages{
font-size: 1.6em;
display: grid;
grid-gap: 3em;
grid-template-columns: 1fr 1fr;
}
#pages>div>a{
color: #555;
text-decoration: none;
}
#prevPage{
margin-left: auto;
}
#nextPage{
margin-right: auto;
}
msg{
position: fixed;
left: 50%;
top: -100px;
transform: translateX(-50%);
z-index: 4;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #ccc;
border-radius: 0.7em;
padding: 0.5em 1em;
/* Leaving animation */
animation: move;
animation-duration: 3s;
}
msg.neutral{
background-color: white;
color: black;
}
@keyframes move {
15% {
top: 20%;
}
95%{
top: 20%;
}
100% {
top: -50px;
}
}
/* @tagging people */
.userRefLink{
color: inherit;
text-decoration: none;
}
.userRefLink:hover{
text-decoration: underline;
}
/* Notifs */
#right{
text-align: center;
align-self: start;
line-height: 1.3em;
}
#notifAdminMsg{
font-size: 0.9em;
}
#notifAdder{
width: calc(100% - 0.6em);
margin-top: 1em;
font-size: 1em;
border-radius: 0.3em;
border: 1px solid #ccc;
padding: 0.3em;
}
.notifTitle{
margin: 0;
}
.notif{
margin-top: 0.5em;
margin-bottom: 0;
}
.deletable{
color: inherit;
text-decoration: none;
}
.deletable:hover{
color: red;
text-decoration: line-through;
}
/* Mentions (alerts) */
.alert{
color: inherit;
text-decoration: none;
display: block;
margin-bottom: 0.4em;
}
.alert:hover{
text-decoration: underline;
}
/* ------------- For the top bar ------------- */
#topSpacer{
height: 2em;
padding: 1% 0;
}
#top{
text-align: center;
display: grid;
grid-template-columns: 1fr 8fr 1fr 1fr;
height: 2em;
align-items:center;
padding: 1% 5%;
width: 90%;
margin: 0 auto;
background-color: white;
position: fixed;
top: 0;
z-index: 8;
box-shadow: 0 1px 2px #ddd;
}
#top>*{
margin: auto;
}
/* Left-side logo */
#logoLink{
display: flex;
}
#logo{
height: 2em;
margin: 0 auto 0 0;
}
/* Search bar */
#search{
margin: auto 0;
}
#searchBar{
border-radius: 0.3em;
width: 80%;
height: 2em;
padding: 2px 10px 0px 10px;
font-size: 1em;
background-color: #f4f4f4;
border: 0;
outline-width: 0;
color: #444;
margin: auto 0;
}
#searchBar::-webkit-input-placeholder {
color: #999 !important;
}
#searchBar:-moz-placeholder { /* Firefox 18- */
color: #999 !important;
}
#searchBar::-moz-placeholder { /* Firefox 19+ */
color: #999 !important;
}
#searchBar:-ms-input-placeholder {
color: #999 !important;
}
/* Add post button */
#addPost{
cursor: pointer;
margin: 0 auto;
height: 100%;
border-radius: 0.3em;
}
#addPost>a{
color: #00d09f;
display: block;
text-decoration: none;
padding: 0.5em 1em;
}
#addPost:hover{
background-color: #f4f4f4;
}
/* Right-side account image */
#accountWrapper{
height: inherit;
margin: auto 0 auto auto;
border-radius: 50%;
}
#account{
border-radius: 50%;
height: inherit;
margin: auto 0 auto auto;
}
/*Tooltips*/
.tooltip {
position: relative;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -60px;
opacity: 0;
transition: opacity 0.3s;
}
.tooltip .tooltiptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}

16
test.php Normal file
View File

@@ -0,0 +1,16 @@
<html>
<head>
<style>
*{margin:0;padding:0}
html, body {height:100%;width:100%;overflow:hidden}
</style>
<meta charset="utf-8">
<?php
$url = "https://ib.lukeogburn.com/forum/images/V6HlWc.docx";
?>
<title><?php echo $url; ?></title>
</head>
<body>
<iframe src="http://docs.google.com/gview?url=<?=$url?>&embedded=true" style="width:600px; height:500px;" frameborder="0"></iframe>
</body>
</html>

0
unset.css Normal file
View File

28
user/banned.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
$GLOBALS["page"] = "banned";
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
if(getUserInfo($current_user)->special!="banned"){
$title = "<h2>YOU HAVE NOT BEEN BANNED</h2>";
$message = "<p class=smallWidth>Why are you even here?</p>";
}else{
$title = "<h2>YOU HAVE BEEN BANNED</h2>";
$message = "<p class=smallWidth>An admin has banned you and left the following message:</p>\n<p class=smallWidth><i>".getUserInfo($current_user)->ban_reason."</i></p>";
}
?>
<!DOCTYPE html>
<html>
<?php
include "../res/head";
?>
<body>
<?php
include "../res/top";
?>
<div id=monoContainer>
<div class="card noHover center">
<?=$title?>
<?=$message?>
</div>
</div>
</body>
</html>

76
user/callback.php Normal file
View File

@@ -0,0 +1,76 @@
<?php
require_once("config.php");
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
if($GLOBALS["verified"]){
//No idea what this used to do, but I'm scared to get rid of it
//header("Location: https://ib.lukeogburn.com/user/?user=".$_COOKIE["IBSITE_ID"]);
}
if(isset($_GET['code'])) {
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
} else {
reportError('callback.php: $_GET["code"] was not set!');
msg("Internal error. It has been reported.");
header("Location: /");
}
$oAuth = new Google_Service_Oauth2($client);
$user = $oAuth->userinfo->get();
//Adding cookie token thing
conn();
$stmt = $conn->prepare("INSERT INTO login_tokens (token, user_id) VALUES (:ac, :id)");
$id = substr($user->email, 0, strlen("@students.hcps.us"));
$access = password_hash($token["access_token"], PASSWORD_DEFAULT);
$stmt->bindParam(':ac', $access);
$stmt->bindParam(':id', $id);
$stmt->execute();
//Updating last login timestamp
$stmt = $conn->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = :id");
$stmt->bindParam(':id', $id);
$stmt->execute();
setcookie("IB_SESSION", $token["access_token"], time() + (60*60*24*14), "/", NULL, true, true);
setcookie("IB_ID", substr($user->email, 0, strlen("@students.hcps.us")), time() + (60*60*24*14), "/", NULL, true, true);
//Checking if user is in database
$dbID = getUserInfo($id)->id; //$id from above used
if(substr($user->email, -7) != "hcps.us"){
header("Location: https://ib.lukeogburn.com/user/reqHcps.php");
}else if($id!=$dbID){
//putting user in database if they aren't already
$stmt = $conn->prepare("INSERT INTO users (id, name, image_url, teacher) VALUES (:id, :nm, :im, :tc)");
$stmt->bindParam(':id', $id);
$name = str_replace(" ", "_", $user["name"]);
$stmt->bindParam(':nm', $name);
$stmt->bindParam(':im', $user["picture"]);
$teacher = is_numeric($id)?NULL:true;
$stmt->bindParam(':tc', $teacher);
$stmt->execute();
if(!$stmt){
reportError("Error signing in (013)");
msg("Error. Try again, maybe? This has been reported.");
header("Location: /");
}
msg("You have been logged in");
header("Location: https://ib.lukeogburn.com/forum/");
}else{
//updating the user's profile picture just in case they changed it in Google
$stmt = $GLOBALS['conn']->prepare("UPDATE users SET image_url = :im WHERE id = :id");
$stmt->bindParam(':im', $user->picture);
$stmt->bindParam(':id', $id);
$result = $stmt->execute();
if(!$result){
reportError("Error in callback - code 014");
msg("Error. It has been reported. Try again, maybe?");
header("Location: /");
}
msg("You have been logged in");
header("Location: https://ib.lukeogburn.com/forum/");
}
?>

8
user/config.php Normal file
View File

@@ -0,0 +1,8 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT']."/googleApi/vendor/autoload.php");
$client = new Google_Client();
$client->setAuthConfig($_SERVER['DOCUMENT_ROOT'].'/googleApi/creds.json');
$client->addScope(Google_Service_Oauth2::PLUS_LOGIN);
$client->addScope(Google_Service_Oauth2::USERINFO_EMAIL);
$client->setRedirectUri("https://ib.lukeogburn.com/user/callback.php");
?>

9
user/finishLogout.php Normal file
View File

@@ -0,0 +1,9 @@
<?php
if(!isset($_COOKIE['IB_ID']) && !isset($_COOKIE['IB_SESSION'])){
header("Location: /");
}else{
reportError("Error in /user/finishLogout.php");
msg("There was an error logging you out. It has been reported.");
header("Location: /");
}
?>

211
user/index.php Normal file
View File

@@ -0,0 +1,211 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
$row = getUserInfo($_GET["user"]);
$id = $row->id;
$name = $row->name;
$classes = $row->classes;
$grade = $row->grade;
$image = $row->image_url;
$teacher = $row->teacher;
if($_COOKIE["IB_ID"]==$_GET['user']){
$accountOwner = true;
}else{
$accountOwner = false;
}
if($id == NULL){
msg("User doesn't exist.");
header('Location: https://ib.lukeogburn.com/forum/');
}
?>
<!DOCTYPE html>
<html>
<?php
$css = 'user';
include $_SERVER['DOCUMENT_ROOT']."/res/head";
?>
<body>
<?php
include $_SERVER['DOCUMENT_ROOT']."/res/top";
function a($type){
$check = $_GET['type']=="" ? "forum" : $_GET['type'];
echo $type == $check ? "active" : "";
}
?>
<div id=userTopWrapper>
<div id=userTop>
<a class=userTopSel <?php a("forum"); ?> href=<?php echo "?user=".$_GET["user"]; ?>&type=forum>POSTS</a>
<a class=userTopSel <?php a("saved"); ?> href=<?php echo "?user=".$_GET["user"]; ?>&type=saved>SAVED</a>
</div>
</div>
<!-- Begin mobile-only part -->
<div id=right class=mobileOnly>
<div id=userInfo class="card noHover">
<div id=userInfoTop>
<img id=userImg src=<?php echo $image; ?>>
<div class=infoDump>
<h2><?php echo $name; ?></h2>
<p><?php
$grade = $teacher?"Teacher":$grade;
echo $grade==null?"Grade level unknown":ucwords($grade);
echo verifyUser("admin", $_GET["user"])?" | Admin":"";
?></p>
<p><?=$_GET["user"]?>@hcps.us</p>
<p><?=$numOfPosts;?></p>
</div>
</div>
</div>
<?php
if(!$teacher){
echo "<div id=userClassInfo class='card noHover'>
<div id=userClassInfoTop class=infoDump>
<h2>Classes</h2>\n";
if($classes==NULL){
echo "<p>Unknown</p>";
}else{
$classesArray= explode(",", $classes);
foreach($classesArray as $class){
$class = ucwords(str_replace("_", " ", $class));
echo "<p>$class</p>";
}
}
echo "</div>
</div>\n";
}
if($accountOwner){
if(verifyUser("admin")){
$admin = "<p><a href=/admin/portal/>Admin Portal</a></p>";
}
echo "<div id=userActionsWrapper class='card noHover'>
<div id=userActions>
<p><a href=/user/logout.php>Logout</a></p>
<p><a href=/user/settings.php>Account Settings</a></p>
<p><a href=/report.php>Report Site Issue</a></p>
$admin
</div>
</div>";
}
?>
</div>
<!-- End mobile-only part -->
<div id=container>
<div id=left>
<?php
$limit = 20;
$page = is_numeric($_GET["page"])&&$_GET["page"]>0?$_GET["page"]:1;
$start = $limit * ($page - 1);
//setting amount of posts allowed on page
if($_GET["type"]=="saved"){
//Getting the saved posts
conn();
$stop = $limit+1;
$stmt = $conn->prepare("SELECT * FROM bookmarks WHERE user_id = :uid ORDER BY unused_id DESC LIMIT $start,$stop");
$stmt->bindParam(":uid", $_GET["user"]);
$stmt->execute();
$row = $stmt->fetchAll();
$count = $stmt->rowCount();
$row = array_slice($row, 0, $limit);
foreach($row as $thing){
$stmt = $conn->prepare("SELECT * FROM forums WHERE post_id = :pid");
$stmt->bindParam(":pid", $thing["post_id"]);
$stmt->execute();
$post = $stmt->fetchAll();
makePost($post[0]);
}
if($count == 0){
$referer = $accountOwner?"your":getUserInfo($_GET["user"])->name."'s";
echo "<h3 class='center noSelect' style=color:#888;font-style:italic;margin-top:10vh;>This is where ".$referer." saved posts would be</h3>";
}
}else{
//Getting user's posts
conn();
$stop = $limit+1;
$stmt = $conn->prepare("SELECT * FROM forums WHERE poster_id = :pid ORDER BY date DESC LIMIT $start,$stop");
$stmt->bindParam(":pid", $_GET["user"]);
$stmt->execute();
$row = $stmt->fetchAll();
$count = $stmt->rowCount();
$row = array_slice($row, 0, $limit);
foreach($row as $post){
makePost($post);
}
}
//Getting how many posts the user has made
$stmt = $conn->prepare("SELECT COUNT(*) FROM forums WHERE poster_id = :id");
$stmt->bindParam(":id", $_GET["user"]);
$stmt->execute();
$numOfPosts = $postCount = $stmt->fetchColumn(0);
$numOfPosts = $numOfPosts==1?"$numOfPosts Post":"$numOfPosts Posts";
if($postCount == 0 && $_GET["type"]!="saved"){
$referer = $accountOwner?"your":getUserInfo($_GET["user"])->name."'s";
echo "<h3 class='center noSelect' style=color:#888;font-style:italic;margin-top:10vh;>This is where ".$referer." posts would be</h3>";
}
//Page arrows
echo "<div id=pages>";
$user = $_GET["user"];
$type = $_GET["type"];
echo $page!=1?"<div id=prevPage><a href=/user/?user=$user&type=$type&page=".($page-1).">&larr;</a></div>":"<div></div>";
echo $count>$limit?"<div id=nextPage><a href=/user/?user=$user&type=$type&page=".($page+1).">&rarr;</a></div>":"<div></div>";
echo "</div>";
?>
</div>
<div id=right>
<div id=userInfo class="card noHover">
<div id=userInfoTop>
<img id=userImg src=<?php echo $image; ?>>
<div class=infoDump>
<h2><?php echo $name; ?></h2>
<p><?php
$grade = $teacher?"Teacher":$grade;
echo $grade==null?"Grade level unknown":ucwords($grade);
echo verifyUser("admin", $_GET["user"])?" | Admin":"";
?></p>
<p><?=$_GET["user"]?>@hcps.us</p>
<p><?=$numOfPosts;?></p>
</div>
</div>
</div>
<?php
if(!$teacher){
echo "<div id=userClassInfo class='card noHover'>
<div id=userClassInfoTop class=infoDump>
<h2>Classes</h2>\n";
if($classes==NULL){
echo "<p>Unknown</p>";
}else{
$classesArray= explode(",", $classes);
foreach($classesArray as $class){
$class = ucwords(str_replace("_", " ", $class));
echo "<p>$class</p>";
}
}
echo "</div>
</div>\n";
}
if($accountOwner){
if(verifyUser("admin")){
$admin = "<p><a href=/admin/portal/>Admin Portal</a></p>";
}
echo "<div id=userActionsWrapper class='card noHover'>
<div id=userActions>
<p><a href=/user/logout.php>Logout</a></p>
<p><a href=/user/settings.php>Account Settings</a></p>
<p><a href=/report.php>Report Site Issue</a></p>
$admin
</div>
</div>";
}
?>
</div>
</div>
</body>
</html>

7
user/login.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
require_once("config.php");
$authUrl = $client->createAuthUrl();
header("Location: ".$authUrl);
?>

13
user/logout.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
$stmt = $conn->prepare("DELETE FROM login_tokens WHERE user_id = :tk");
$stmt->bindParam(":tk", $_COOKIE["IB_ID"]);
$stmt->execute();
setcookie("IB_ID", $_COOKIE["IB_ID"], time()-3600, "/");
setcookie("IB_SESSION", $_COOKIE["IB_SESSION"], time()-3600, "/");
header("Location: finishLogout.php");
//Without this, PHP can't tell the cookie was deleted. It's dumb but it works.
?>

59
user/reqHcps.php Normal file
View File

@@ -0,0 +1,59 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
conn();
$stmt = $conn->prepare("DELETE FROM login_tokens WHERE user_id = :tk");
$stmt->bindParam(":tk", $_COOKIE["IB_ID"]);
$stmt->execute();
setcookie("IB_ID", $_COOKIE["IB_ID"], time()-3600, "/");
setcookie("IB_SESSION", $_COOKIE["IB_SESSION"], time()-3600, "/");
?>
<html>
<head>
<?php
include $_SERVER['DOCUMENT_ROOT']."/res/head";
?>
<style>
#error{
color: red;
margin-top: 10%;
}
.link{
text-decoration: none;
display: inline;
}
.link:hover{
cursor: pointer;
text-decoration: underline;
}
#ebody{
margin: 0 15%;
text-align: center;
}
</style>
</head>
<body>
<?php
require $_SERVER['DOCUMENT_ROOT']."/res/top";
?>
<div id=ebody>
<h3 id=error>You need to use your school account.</h3>
<br><!-- so -->
<p class=link>(<a class=link href=login.php>Back to login page</a>)</p>
<br><!-- sorry -->
<br><!-- for -->
<br><!-- this -->
<p>
If you weren't given the option, you need to:<br>
<div style=display:inline-block;margin-left:auto;margin-right:auto;>
<ol style=text-align:left;>
<li>Go to <a class=link target=_BLANK href=https://google.com/>google.com</a></li>
<li>Sign in with your HCPS account</li>
<li>Re-login here</li>
</ol>
</div>
</p>
</div>
</body>
</html>

101
user/settings.php Normal file
View File

@@ -0,0 +1,101 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
if(!(isset($_COOKIE["IB_ID"]))){
header("Location: https://ib.lukeogburn.com/user/login.php");
}
conn();
$stmt = $GLOBALS['conn']->prepare("SELECT * FROM users WHERE id = :id");
$id = $current_user;
$stmt->bindParam(":id", $id);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_OBJ);
$GLOBALS['grade'] = $row->grade;
$GLOBALS['userClasses'] = explode(",", $row->classes);
$GLOBALS['name'] = $row->name;
$GLOBALS['teacher'] = $row->teacher;
$GLOBALS['dark_theme'] = $row->dark_theme;
$GLOBALS['snow'] = $row->snow;
function dt($val){
if($val == $GLOBALS['dark_theme']){
return "checked";
}
}
function sw($val){
if($val == $GLOBALS['snow']){
return "checked";
}
}
?>
<!DOCTYPE html>
<html>
<?php
$css = "updateInfo";
include $_SERVER['DOCUMENT_ROOT']."/res/head";
?>
<body>
<?php
include $_SERVER['DOCUMENT_ROOT']."/res/top";
?>
<div id=monoContainer>
<div class='card noHover center'>
<h2>Account Settings</h2>
<form method=POST action="updateFunc.php">
<p class=question>Dark theme?</p>
<input type=radio name=dark_theme id=darkThemeOff value=0 <?=dt(0)?>>
<label class=sideBySide for=darkThemeOff>OFF</label>
<input type=radio name=dark_theme id=darkThemeOn value=1 <?=dt(1)?>>
<label class=sideBySide for=darkThemeOn>ON</label>
<p class=question>Snow?</p>
<input type=radio name=snow id=snowOff value=0 <?=sw(0)?>>
<label class=sideBySide for=snowOff>OFF</label>
<input type=radio name=snow id=snowOn value=1 <?=sw(1)?>>
<label class=sideBySide for=snowOn>ON</label>
<p class=question>What is your name?</p>
<input type=text name=name autocomplete=off maxlength=20 placeholder="Your name" value=<?php echo "\"".$GLOBALS['name']."\""; ?>>
<?php
function a($level){
if($level == $GLOBALS['grade']){
return "checked";
}
}
function b($class){
if(in_array($class, $GLOBALS['userClasses'])){
return "checked";
}
}
if($GLOBALS['teacher'] == NULL){
echo "
<p class=question>What grade level are you?</p>
<input type=radio name=grade id=fm value=freshman ".a('freshman')." >
<label for=fm>Freshman</label>
<input type=radio name=grade id=sp value=sophmore ".a('sophmore')." >
<label for=sp>Sophmore</label>
<input type=radio name=grade id=jr value=junior ".a('junior')." >
<label for=jr>Junior</label>
<input type=radio name=grade id=sn value=senior ".a('senior')." >
<label for=sn>Senior</label>
<p class=question>Which of these classes are you in?</p>";
$classes = file_get_contents($_SERVER['DOCUMENT_ROOT']."/res/classes");
$classes = array_filter(explode(",", $classes));
$tag = 1;
foreach($classes as $class){
echo "<input name=classes[] value=$class type=checkbox id=tag$tag ".b($class)."><label class=tagLabel for=tag$tag>".ucwords(str_replace("_", " ", $class))."</label>\n";
$tag++;
}
}
?>
<button class=save name=btn type=submit value=submit>Save</button>
</form>
</div>
<br> <!-- shows the margin-bottom of the last .card for some reason (also adds another space, which doesn't look horrible so I'm keeping it lol -->
</div>
</body>
</html>

64
user/updateFunc.php Normal file
View File

@@ -0,0 +1,64 @@
<?php
require $_SERVER['DOCUMENT_ROOT']."/globalFuncs.php";
//Getting class settings
$i=0;//for the comma
if(isset($_POST['classes'])){
foreach($_POST['classes'] as $class){
if($i==1){//for the comma
$classes .= ",";
}else{
$i=1;
}
$classes .= $class;
}
}else{
$classes = "";
}
$id = $current_user;
//Making sure username is legal
if(strlen($_POST["name"])>20){
msg("You cannot have a name with more than 20 characters");
header("Location: /user/updateInfo.php");
exit();
}else if(strContains($_POST["name"], " ")){
msg("You cannot have a space in your username");
header("Location: /user/updateInfo.php");
exit();
}else if(preg_match('#[^a-zA-Z0-9\-_]+#', $_POST["name"])){
preg_match_all('#[^a-zA-Z0-9\-_]#', $_POST["name"], $match);
for($i=0; $i<sizeof($match[0]);$i++){
$char .= $match[0][$i].", ";
}
$char = substr($char, 0, -2);
msg("Please only use -, _, and alphanumeric characters (don't use $char)");
header("Location: /user/settings.php");
exit();
}
//Making sure the username isn't taken
if(getUserInfoByName($_POST["name"])->name != "" && getUserInfoByName($_POST["name"])->id != $id){
msg("That name is already taken");
header("Location: /user/updateInfo.php");
exit();
}
//Actually putting the info in the database
conn();
$stmt = $GLOBALS['conn']->prepare("UPDATE users SET name = :nm, grade = :gd, classes = :cs, dark_theme = :dt, snow = :sw WHERE id = :id");
$stmt->bindParam(":nm", $_POST["name"]);
$stmt->bindParam(":gd", $_POST["grade"]);
$stmt->bindParam(":cs", $classes);
$stmt->bindParam(":dt", $_POST["dark_theme"]);
$stmt->bindParam(":sw", $_POST["snow"]);
$stmt->bindParam(":id", $id);
$stmt->execute();
if($stmt){
msg("Information updated");
}else{
reportError("Error given at end of /user/updateFunc.php");
msg("Error updating. It has been reported.");
}
header("Location: https://ib.lukeogburn.com/user/?user=".$id);
?>

80
user/updateInfo.css Normal file
View File

@@ -0,0 +1,80 @@
html, body{
height: calc(100% - 1em);
/* Allows the body content be centered vartically.
No idea why the "-1em" part matters, but it does and it works so don't touch it unless you are willing to see the proccess through
*/
}
#midtainer{
display: flex;
height: calc(100% - 2em - 4%);
/* 100% - top bar thing */
align-items: center;
justify-content: center;
}
#updateCard{
display: inline-block;
padding: 2em 4em;
margin: 5% auto;
text-align: center;
}
.question{
font-size: 1.1em;
margin-top: 2em;
margin-bottom: 0.7em;
}
select{
padding: 0.3em 2em;
align-items: center;
justify-content: center;
background-color: #eee;
border: none;
outline-width: 0;
font-size: 0.9em;
}
option{
text-align: center;
}
form>label:not(.sideBySide){
margin-left: auto;
margin-right: auto;
}
form>label:not(.sideBySide){
display: block;
}
.sideBySide{
display: inline;
}
.sideBySide:not(:last-of-type){
margin-right: 1%;
}
input[type=checkbox], input[type=radio]{
display: none;
}
.tagLabel{
display: inline-block;
}
label:not(:last-of-type){
margin-bottom: 0.3em;
}
input[type=checkbox]:checked+label, input[type=radio]:checked+label{
color: #00d09f;
}
input[type=text]:not(#searchBar){
border: none;
border-bottom: 1px solid black;
outline-width: 0;
text-align: center;
font-size: 1em;
margin-bottom: calc(1em + 1px);
}
button[type=submit]{
font-size: 1em;
background-color: white;
color: #00d09f;
border: 1px solid #00d09f;
padding: 0.5em 1em;
margin-top: 2em;
}
label:hover, button:hover{
cursor: pointer;
}

76
user/user.css Normal file
View File

@@ -0,0 +1,76 @@
#container{
grid-template-columns: 2fr 1fr;
}
/* General forum stuff */
.forumLink{
text-decoration: none;
}
/* Choosing section to view */
#userTopWrapper{
height: 2em;
background-color: white;
box-shadow: 0 1px 3px #ddd;
display: flex;
justify-content: center;
align-items: center;
position: relative;
z-index: 5;
}
.userTopSel{
color: black;
text-decoration: none;
margin: 0 1em 2px 1em;
}
.userTopSel[active]{
margin-bottom: 0;
padding-bottom: 1px;
border-bottom: 2px solid #00d09f;
border-radius: 0.2em;
}
.userTopSel:hover:not([active]){
margin-bottom: 0;
border-bottom: 2px solid #2ce4b9;
border-radius: 0.2em;
}
#top{
box-shadow: none; /* Overriding the top bar's shadow */
}
/*Didn't know where to put these so I put it here*/
#userImg{
border-radius: 50%;
}
#userActions>p>a{
color: inherit;
text-decoration: none;
}
#userActions>p>a:not(:first-of-type){
margin-top: 0.6em;
}
#userActions>p>a:hover{
text-decoration: underline;
}
/* User info */
#right{
background-color: rgba(0,0,0,0);
padding: 0;
margin: 0;
border: none;
box-shadow: none;
}
.infoDump>h2{
text-overflow: ellipsis;
}
#userImg{
width: 30%;
display: block;
margin: 0 auto;
}
.infoDump{
display: block;
}
.infoDump>p{
text-align: center;
margin: 0;
margin-top: 0.7em;
}