Skip to content

Oraql is a website for users to ask and answer questions about supernatural phenomena. It is inspired by Quora.

Notifications You must be signed in to change notification settings

starsabhi/Oraql

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Oraql

Oraql is a website for users to ask and answer questions about supernatural phenomena. It is inspired by Quora.

Try asking and answering questions at our live site: Oraql

Index

| MVP Feature List | Database Schema | API Documentation | Frontend Routes | User Stories |

Technologies Used

Getting started

  1. Clone this repository

    git clone [email protected]:starsabhi/Oraql.git

  2. Install dependencies

    npm install

  3. Create a .env file based on the .env.example given

  4. Setup your username and database based on what you setup in your .env

  5. Migrate and Seed models

    npx dotenv sequelize db:migrate && npx dotenv sequelize db:seed:all

  6. Start the app using:

    npm start

  7. You can use the Demo user or create an account

Features

Oraql is a question-and-answer website for users to post/edit/delete questions and answers. Logged in sers can dynamically edit and delete answers without redirecting.

Logged out users can:

  • View Questions and Associated Answers
  • Search for Questions
  • View Questions by Topics/Tags

Logged in users can:

  • Add/Edit/Delete Questions
  • Add/Edit/Delete Answers
  • Search for Questions
  • View Questions by Topics/Tags

Home Page

image

User Sign Up Page

image

Add Question Page

image

Question Detail Page

image

Search Results Page

image

Future Features

  • Comments on Answers:
    • Logged-in users can add comments on answers.
    • Logged-in users can upvote comments/answers/questions.
  • Likes on Questions/Answers/Comments
    • Logged-in users can remove their own like from questions/answers/comments.
    • All users can see how many users have liked a question/answer/comment.
  • User profiles

Technical Implementation

  • One of our first challenges was search bar functionality: how to process an input and search for related information in the database. Our solution is to segment the input string into a list of words and query the question.content column for data containing any of the words.
router.post(
  "/results",
  inputValidators,
  asyncHandler(async (req, res) => {
    let words = req.body.searchText.trim().split(/\s+/);

    const validatorErrors = validationResult(req);

    if (!validatorErrors.isEmpty()) {
      backURL = req.header("Referer") || "/";
      return res.redirect(backURL);
    }

    words = words.map((word) => `%${word}%`);
    const questions = await db.Question.findAll({
      where: {
        content: {
          [Op.iLike]: {
            [Op.any]: words,
          },
        },
      },
      include: [{ model: db.User }, { model: db.Tag }],
      order: [["createdAt", "DESC"]],
    });

    res.render("search-results", {
      title: "Search Results",
      questions,
      search: req.body.searchText,
    });
  })
);
  • The other challenge was how to display a question and a list of answers on the question which are sorted by createdAt date. Our solution is to perform an eager loading to query of several different models, including Question, Answer and User, at once. Then we sort the answers of a question by createdAt and display the sorted answer on the page.
router.get(
  "/:id(\\d+)",
  asyncHandler(async (req, res) => {
    const questionId = parseInt(req.params.id, 10);
    const question = await db.Question.findByPk(questionId, {
      include: [
        db.User,
        {
          model: db.Answer,
          include: db.User,
        },
        db.Tag,
      ],
    });

    const answers = question.Answers;
    answers.sort((a, b) => {
      const keyA = new Date(a.createdAt);
      const keyB = new Date(b.createdAt);
      return keyA < keyB ? -1 : 1;
    });

    answers.forEach((answer) => {
      answer.date = answer.createdAt.toDateString();
    });

    res.render("question-detail", {
      title: question.content,
      question,
      answers,
    });
  })
);
  • custom validations on sign up input
const userValidators = [
  check("username")
    .exists({ checkFalsy: true })
    .withMessage("Please provide a value for Username")
    .isLength({ max: 20 })
    .withMessage("Username must not be more than 20 characters long")
    .custom((value) => {
      return db.User.findOne({ where: { username: value } }).then((user) => {
        if (user) {
          return Promise.reject(
            "The provided Username is already in use by another account"
          );
        }
      });
    })
    .custom((value) => !/^ *$/.test(value))
    .withMessage("Username cannot be empty"),
];
  • Dynamically update answers without redirection
submitBtn.addEventListener("click", async (submitEvent) => {
    submitEvent.preventDefault();
    const contentValue = document.getElementById(
      `${answerId}-edit-content`
    ).value;

    const questionId = parseInt(
      submitEvent.target.classList[0].split("-")[1],
      10
    );

    const res = await fetch(`/questions/${questionId}/answers/${answerId}`, {
      method: "PUT",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        content: contentValue,
      }),
    });

    const data = await res.json();
    if (data.message === "Success") {
      let contentEle = document.getElementById(`answer-content-${answerId}`);
      let lines = data.answer.content.split("\n");
      lines = lines.map((line) => `<div>${line}</div>`);
      contentEle.innerHTML = lines.join("");

      form.classList.add("hidden");
      answerContent.classList.remove("hidden");
      editAnswerButton.classList.remove("hidden");
      deleteAnswerButton.classList.remove("hidden");
    } else {
      if (data.message === "Failure") {
        const errorDiv = document.getElementById(`edit-errors-${answerId}`);
        errorDiv.innerHTML = data.errors[0];
      }
    }
});

About

Oraql is a website for users to ask and answer questions about supernatural phenomena. It is inspired by Quora.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •