Changeset af801e3


Ignore:
Timestamp:
12/08/22 22:44:02 (2 years ago)
Author:
viktor <viktor@…>
Branches:
main
Children:
a5aba17
Parents:
3b6962d
Message:

finished edit/delete/displace opinion/thread from report (react); todo reporting user/opinion/thread interface, public user pages and messaging (springboot)

Files:
4 added
19 edited

Legend:

Unmodified
Added
Removed
  • reactapp/src/App.js

    r3b6962d raf801e3  
    1414import NotFound from "./Pages/NotFound";
    1515import Topic from "./Pages/Topic";
     16import LoadingSpinner from "./Components/Styled/LoadingSpinner.style";
    1617
    1718export default function App() {
     
    4243      return children;
    4344    } else {
    44       return <div>се вчитува cookie...</div>;
     45      return <LoadingSpinner/>;
    4546    }
    4647  };
  • reactapp/src/Components/OpinionTree.js

    r3b6962d raf801e3  
    4242
    4343  useEffect(() => {
    44     const url = `http://192.168.0.19:8080/secure/currentUser`;
     44    const url = `http://192.168.0.29:8080/secure/currentUser`;
    4545
    4646    const fetchUser = async () => {
     
    6868      ) {
    6969        const response = await axios(
    70           `http://192.168.0.19:8080/secure/upvoteOpinion/${post.postId}`,
     70          `http://192.168.0.29:8080/secure/upvoteOpinion/${post.postId}`,
    7171          {
    7272            method: "get",
     
    7474          }
    7575        );
    76         window.location.reload(false);
     76        window.location.reload();
    7777      } else {
    7878        return;
     
    9191      ) {
    9292        const response = await axios(
    93           `http://192.168.0.19:8080/secure/downvoteOpinion/${post.postId}`,
     93          `http://192.168.0.29:8080/secure/downvoteOpinion/${post.postId}`,
    9494          {
    9595            method: "get",
     
    9898        );
    9999
    100         window.location.reload(false);
     100        window.location.reload();
    101101      } else {
    102102        return;
     
    131131    if (!replyContent.length < 1) {
    132132      const response = await axios(
    133         `http://192.168.0.19:8080/secure/professor/${professor.professorId}/replyToOpinion/${postId}`,
     133        `http://192.168.0.29:8080/secure/professor/${professor.professorId}/replyToOpinion/${postId}`,
    134134        {
    135135          method: "post",
     
    141141      );
    142142      setErrorMessage("");
    143       window.location.reload(false);
     143      window.location.reload();
    144144    } else {
    145145      setErrorMessage("Полето за содржина не смее да биде празно");
     
    161161              {child.content}
    162162            </p>
    163             {child.timePosted === child.timeLastEdited ? (
     163            {new Date(child.timePosted).setMilliseconds(0) === new Date(child.timeLastEdited).setMilliseconds(0) ? (
    164164              <OpinionCardContentTime>
    165165                {dateConverter(
    166166                  new Date(child.timePosted).toString().slice(4, -43)
    167                 )}
     167                )} <span style={{fontStyle:"normal",color:"blue"}}>#{child.postId}</span>
    168168              </OpinionCardContentTime>
    169169            ) : (
     
    171171                {dateConverter(
    172172                  new Date(child.timeLastEdited).toString().slice(4, -43)
    173                 )}{" "}
     173                )}{" "} <span style={{fontStyle:"normal",color:"blue"}}>#{child.postId}</span>{" "}
    174174                (едитирано од модератор)
    175175              </OpinionCardContentTime>
     
    260260                    {opinion.content}
    261261                  </p>
    262                   {opinion.timePosted === opinion.timeLastEdited ? (
     262                  {new Date(opinion.timePosted).setMilliseconds(0) === new Date(opinion.timeLastEdited).setMilliseconds(0) ? (
    263263                    <OpinionCardContentTime>
    264264                      {dateConverter(
    265265                        new Date(opinion.timePosted).toString().slice(4, -43)
    266                       )}
     266                      )} <span style={{fontStyle:"normal",color:"blue"}}>#{opinion.postId}</span>
    267267                    </OpinionCardContentTime>
    268268                  ) : (
     
    272272                          .toString()
    273273                          .slice(4, -43)
    274                       )}{" "}
     274                      )}{" "} <span style={{fontStyle:"normal",color:"blue"}}>#{opinion.postId}</span>{" "}
    275275                      (едитирано од модератор)
    276276                    </OpinionCardContentTime>
  • reactapp/src/Components/Search.js

    r3b6962d raf801e3  
    1515
    1616  useEffect(() => {
    17     const url = `http://192.168.0.19:8080/public/professors/nameContains/${transliterate(
     17    const url = `http://192.168.0.29:8080/public/professors/nameContains/${transliterate(
    1818      query
    1919    )}`;
  • reactapp/src/Components/Styled/ProfessorCard.style.js

    r3b6962d raf801e3  
    22
    33export const ProfessorCard = styled.div`
    4   background-color: cornsilk;
    54  width: auto;
    65  padding: 10px;
  • reactapp/src/Components/UserHeader.js

    r3b6962d raf801e3  
    33import axios from "../api/axios";
    44import Logout from "./Logout";
     5import LoadingSpinner from "./Styled/LoadingSpinner.style";
    56
    67function UserHeader({}) {
     
    1011
    1112  useEffect(() => {
    12     const url = `http://192.168.0.19:8080/secure/currentUser`;
     13    const url = `http://192.168.0.29:8080/secure/currentUser`;
    1314
    1415    const fetchUser = async () => {
     
    3435  ) : (
    3536    <div style={{ float: "left", marginTop: 25, marginLeft: 60 }}>
    36       се вчитува...
     37      <LoadingSpinner/>
    3738    </div>
    3839  );
  • reactapp/src/Pages/Faculty.js

    r3b6962d raf801e3  
    1616import SubjectsAccordion from "../Components/SubjectsAccordion";
    1717import { CurrentPageNav } from "../Components/Styled/Main.style";
     18import LoadingSpinner from "../Components/Styled/LoadingSpinner.style";
    1819
    1920const Faculty = () => {
     
    2728
    2829  useEffect(() => {
    29     const urlProfessors = `http://192.168.0.19:8080/public/professors?facultyId=${params.facultyId}`;
    30     const urlStudyProgrammes = `http://192.168.0.19:8080/public/study_programmes?facultyId=${params.facultyId}`;
     30    const urlProfessors = `http://192.168.0.29:8080/public/professors?facultyId=${params.facultyId}`;
     31    const urlStudyProgrammes = `http://192.168.0.29:8080/public/study_programmes?facultyId=${params.facultyId}`;
    3132
    3233    const fetchDataProfessors = async () => {
     
    224225  ) : !fetchError && !loadedProfessors ? (
    225226    <div>
    226       <p style={{ marginTop: "140px" }}>се вчитува...</p>
     227      <LoadingSpinner style={{ marginTop: "140px" }}/>
    227228      <Outlet />
    228229    </div>
  • reactapp/src/Pages/Login.js

    r3b6962d raf801e3  
    1717
    1818  useEffect(() => {
    19     userRef.current.focus();
     19    if (!auth) userRef.current.focus();
    2020  }, []);
    2121
  • reactapp/src/Pages/Professor.js

    r3b6962d raf801e3  
    2424import axios from "../api/axios";
    2525import { CurrentPageNav } from "../Components/Styled/Main.style";
     26import LoadingSpinner from "../Components/Styled/LoadingSpinner.style";
    2627
    2728function Professor() {
     
    3940
    4041  useEffect(() => {
    41     const url = `http://192.168.0.19:8080/public/professor/${params.professorId}`;
     42    const url = `http://192.168.0.29:8080/public/professor/${params.professorId}`;
    4243
    4344    const fetchProfessor = async () => {
     
    7677    if (!postContent.length < 1) {
    7778      const response = await axios(
    78         `http://192.168.0.19:8080/secure/professor/${params.professorId}/addOpinion`,
     79        `http://192.168.0.29:8080/secure/professor/${params.professorId}/addOpinion`,
    7980        {
    8081          method: "post",
     
    8687      );
    8788      setErrorMessage("");
    88       window.location.reload(false);
     89      window.location.reload();
    8990    } else {
    9091      setErrorMessage("Полето за содржина не смее да биде празно");
     
    111112        </CurrentPageNav>
    112113        <ProfessorCard>
    113           <ProfessorCardName>{professor.professorName}</ProfessorCardName>
     114          <ProfessorCardName>{professor.professorName} <span style={{opacity:"50%", fontSize:"16px"}}>#{professor.professorId}</span></ProfessorCardName>
    114115          <ProfessorCardSeparator />
    115116          <div style={{ marginTop: "10px" }}>
     
    179180    return (
    180181      <div>
    181         <p style={{ marginTop: "140px" }}>се вчитува...</p>
     182        <LoadingSpinner style={{ marginTop: "140px" }}/>
    182183        <Outlet />
    183184      </div>
  • reactapp/src/Pages/Subject.js

    r3b6962d raf801e3  
    2828} from "../Components/Styled/Modal.style";
    2929import axios from "../api/axios";
     30import LoadingSpinner from "../Components/Styled/LoadingSpinner.style";
    3031
    3132const Subject = () => {
     
    4647
    4748  useEffect(() => {
    48     const url = `http://192.168.0.19:8080/public/subject/${params.subjectId}`;
     49    const url = `http://192.168.0.29:8080/public/subject/${params.subjectId}`;
    4950
    5051    const fetchData = async () => {
     
    8384    if (!topicTitle.length < 1 && !topicContent.length < 1) {
    8485      const response = await axios(
    85         `http://192.168.0.19:8080/secure/subject/${params.subjectId}/addThread`,
     86        `http://192.168.0.29:8080/secure/subject/${params.subjectId}/addThread`,
    8687        {
    8788          method: "post",
     
    9495      );
    9596      setErrorMessage("");
    96       window.location.reload(false);
     97      window.location.reload();
    9798    } else {
    9899      setErrorMessage("Полињата за наслов и содржина не смеат да бидат празни");
     
    127128      </CurrentPageNav>
    128129      <ProfessorCard>
    129         <ProfessorCardName>{subject.subjectName}</ProfessorCardName>
     130        <ProfessorCardName>{subject.subjectName} <span style={{opacity:"50%", fontSize:"16px"}}>#{subject.subjectId}</span></ProfessorCardName>
    130131        <ProfessorCardSeparator />
    131132        <div style={{ marginTop: "10px" }}>
     
    204205      <div key={subject.subjectId}>
    205206        {topics.map((topic) => {
    206           var numReplies = topic.children.length;
     207          var numReplies = 0;
     208          topic.children.map((c)=>numReplies += ++c.children.length); // ++c.children.length -> c + decata na c
    207209          return (
    208210            <EntityUl key={topic.postId}>
     
    268270  ) : !fetchError ? (
    269271    <div>
    270       <p style={{ marginTop: "140px" }}>се вчитува...</p>
     272      <LoadingSpinner style={{ marginTop: "140px" }}/>
    271273      <Outlet />
    272274    </div>
  • reactapp/src/Pages/Topic.js

    r3b6962d raf801e3  
    2828} from "../Components/Styled/Modal.style";
    2929import axios from "../api/axios";
     30import LoadingSpinner from "../Components/Styled/LoadingSpinner.style";
    3031
    3132const Topic = () => {
     
    4849
    4950  useEffect(() => {
    50     const url1 = `http://192.168.0.19:8080/public/thread/${params.topicId}`;
    51     const url2 = `http://192.168.0.19:8080/secure/currentUser`;
     51    const url1 = `http://192.168.0.29:8080/public/thread/${params.topicId}`;
     52    const url2 = `http://192.168.0.29:8080/secure/currentUser`;
    5253
    5354    const fetchTopic = async () => {
     
    99100    if (!replyContent.length < 1) {
    100101      const response = await axios(
    101         `http://192.168.0.19:8080/secure/subject/${thread.targetSubject.subjectId}/replyToThread/${postId}`,
     102        `http://192.168.0.29:8080/secure/subject/${thread.targetSubject.subjectId}/replyToThread/${postId}`,
    102103        {
    103104          method: "post",
     
    109110      );
    110111      setErrorMessage("");
    111       window.location.reload(false);
     112      window.location.reload();
    112113    } else {
    113114      setErrorMessage("Полето за содржина не смее да биде празно");
     
    128129    if (!postContent.length < 1) {
    129130      const response = await axios(
    130         `http://192.168.0.19:8080/secure/subject/${thread.targetSubject.subjectId}/replyToThread/${params.topicId}`,
     131        `http://192.168.0.29:8080/secure/subject/${thread.targetSubject.subjectId}/replyToThread/${params.topicId}`,
    131132        {
    132133          method: "post",
     
    138139      );
    139140      setErrorMessage("");
    140       window.location.reload(false);
     141      window.location.reload();
    141142    } else {
    142143      setErrorMessage("Полето за содржина не смее да биде празно");
     
    160161      ) {
    161162        const response = await axios(
    162           `http://192.168.0.19:8080/secure/upvoteThread/${post.postId}`,
     163          `http://192.168.0.29:8080/secure/upvoteThread/${post.postId}`,
    163164          {
    164165            method: "get",
     
    166167          }
    167168        );
    168         window.location.reload(false);
     169        window.location.reload();
    169170      } else {
    170171        return;
     
    183184      ) {
    184185        const response = await axios(
    185           `http://192.168.0.19:8080/secure/downvoteThread/${post.postId}`,
     186          `http://192.168.0.29:8080/secure/downvoteThread/${post.postId}`,
    186187          {
    187188            method: "get",
     
    190191        );
    191192
    192         window.location.reload(false);
     193        window.location.reload();
    193194      } else {
    194195        return;
     
    213214              {child.content}
    214215            </p>
    215             {thread.timePosted === thread.timeLastEdited ? (
     216            {new Date(child.timePosted).setMilliseconds(0) === new Date(child.timeLastEdited).setMilliseconds(0) ? (
    216217              <OpinionCardContentTime>
    217218                {dateConverter(
    218                   new Date(thread.timePosted).toString().slice(4, -43)
    219                 )}
     219                  new Date(child.timePosted).toString().slice(4, -43)
     220                )} <span style={{fontStyle:"normal",color:"blue"}}>#{child.postId}</span>
    220221              </OpinionCardContentTime>
    221222            ) : (
    222223              <OpinionCardContentTime>
    223224                {dateConverter(
    224                   new Date(thread.timeLastEdited).toString().slice(4, -43)
    225                 )}{" "}
     225                  new Date(child.timeLastEdited).toString().slice(4, -43)
     226                )}{" "} <span style={{fontStyle:"normal",color:"blue"}}>#{child.postId}</span>{" "}
    226227                (едитирано од модератор)
    227228              </OpinionCardContentTime>
     
    270271              />
    271272
    272               <VoteCount right={50 + "px"}>
     273              <VoteCount right={10 + "px"}>
    273274                {child.votes.filter((v) => v.vote === "DOWNVOTE").length}
    274275              </VoteCount>
     
    324325      </CurrentPageNav>
    325326      <div style={{ height: "20px", marginBottom: "50px", marginTop: "50px" }}>
    326         <h3 style={{ float: "left" }}>{thread.title}</h3>
     327        <h3 style={{ float: "left" }}>{thread.title} <span style={{opacity:"50%", fontSize:"16px"}}>#{thread.postId}</span></h3>
    327328        {auth && (
    328329          <AddOpinionButton onClick={handleAddOpinionButtonClick}>
     
    369370            {thread.content}
    370371          </p>
    371           {thread.timePosted === thread.timeLastEdited ? (
     372          {new Date(thread.timePosted).setMilliseconds(0) === new Date(thread.timeLastEdited).setMilliseconds(0) ? (
    372373            <OpinionCardContentTime>
    373374              {dateConverter(
    374375                new Date(thread.timePosted).toString().slice(4, -43)
    375               )}
     376              )} <span style={{fontStyle:"normal",color:"blue"}}>#{thread.postId}</span>
    376377            </OpinionCardContentTime>
    377378          ) : (
     
    379380              {dateConverter(
    380381                new Date(thread.timeLastEdited).toString().slice(4, -43)
    381               )}{" "}
     382              )}{" "} <span style={{fontStyle:"normal",color:"blue"}}>#{thread.postId}</span>{" "}
    382383              (едитирано од модератор)
    383384            </OpinionCardContentTime>
     
    444445                {directChild.content}
    445446              </p>
    446               {directChild.timePosted === directChild.timeLastEdited ? (
     447              {new Date(directChild.timePosted).setMilliseconds(0) === new Date(directChild.timeLastEdited).setMilliseconds(0) ? (
    447448                <OpinionCardContentTime>
    448449                  {dateConverter(
    449450                    new Date(directChild.timePosted).toString().slice(4, -43)
    450                   )}
     451                  )} <span style={{fontStyle:"normal",color:"blue"}}>#{directChild.postId}</span>
    451452                </OpinionCardContentTime>
    452453              ) : (
     
    456457                      .toString()
    457458                      .slice(4, -43)
    458                   )}{" "}
     459                  )}{" "} <span style={{fontStyle:"normal",color:"blue"}}>#{directChild.postId}</span>{" "}
    459460                  (едитирано од модератор)
    460461                </OpinionCardContentTime>
     
    559560  ) : !fetchError && !loadedThread ? (
    560561    <div>
    561       <p style={{ marginTop: "140px" }}>се вчитува...</p>
     562      <LoadingSpinner style={{ marginTop: "140px" }}/>
    562563      <Outlet />
    563564    </div>
  • reactapp/src/Pages/University.js

    r3b6962d raf801e3  
    1414} from "../Components/Styled/EntityList.style";
    1515import { CurrentPageNav } from "../Components/Styled/Main.style";
     16import LoadingSpinner from "../Components/Styled/LoadingSpinner.style";
    1617
    1718const University = () => {
     
    2223
    2324  useEffect(() => {
    24     const url = `http://192.168.0.19:8080/public/faculties?universityId=${params.universityId}`;
     25    const url = `http://192.168.0.29:8080/public/faculties?universityId=${params.universityId}`;
    2526
    2627    const fetchData = async () => {
     
    105106  ) : !fetchError && !loaded ? (
    106107    <div>
    107       <p style={{ marginTop: "140px" }}>се вчитува...</p>
     108      <LoadingSpinner style={{ marginTop: "140px" }}/>
    108109      <Outlet />
    109110    </div>
  • reactapp/src/Pages/UserDashboard.js

    r3b6962d raf801e3  
     1/* eslint-disable no-unused-vars */
     2// noinspection JSUnresolvedVariable,ES6ConvertVarToLetConst,JSUnresolvedFunction,SpellCheckingInspection,JSUnusedLocalSymbols
     3
    14import React, { useEffect, useState, useContext } from "react";
    25import {
     
    2326    ModalInput
    2427} from "../Components/Styled/Modal.style";
     28import LoadingSpinner from "../Components/Styled/LoadingSpinner.style";
    2529
    2630function UserDashboard() {
     
    4044
    4145  const [newPostContent, setNewPostContent] = useState("");
    42   const [newPostTitle, setNewPostTitle] = useState("");
     46  const [newOpinionTargetProfessorId, setNewOpinionTargetProfessorId] = useState("");
     47  const [newOpinionTargetProfessor, setNewOpinionTargetProfessor] = useState(null);
     48  const [loadedNewProfessor,setLoadedNewProfessor] = useState(false);
     49  const [newParentPostId, setNewParentPostId] = useState("-1");
     50
     51  const [newThreadTitle, setNewThreadTitle] = useState("");
     52  const [newParentThreadId,setNewParentThreadId] = useState("-1");
     53  const [newTargetSubjectId, setNewTargetSubjectId] = useState("");
     54  const [newTargetSubject, setNewTargetSubject] = useState(null);
     55  const [loadedNewSubject, setLoadedNewSubject] = useState(null);
    4356
    4457  const [markResolved, setMarkResolved] = useState(false);
     58
     59  const [errMsg, setErrMsg] = useState("");
    4560
    4661  const handleModalCloseClick = () => {
     
    5974      if (reportForModal.post !== null) {
    6075        setNewPostContent(reportForModal.post.content);
    61         if(reportForModal.post.title !== null) setNewPostTitle(reportForModal.post.title);
     76        if(reportForModal.post.title !== null) setNewThreadTitle(reportForModal.post.title);
     77        if(reportForModal.post.targetProfessor !== undefined) setNewOpinionTargetProfessorId(reportForModal.post.targetProfessor.professorId); //prvicnoto
     78        if(reportForModal.post.targetProfessor === undefined) setNewTargetSubjectId(reportForModal.post.targetSubject.subjectId); //prvicnoto
    6279      }
    6380      setReportModalDisplay("block");
     
    6683  }, [reportForModal]);
    6784
     85  const[loadingProf, setLoadingProf] = useState(false);
     86
     87  const handleNewTargetProfessorChange = async (e) => {
     88    setLoadingProf(true);
     89    e.preventDefault();
     90    if (newOpinionTargetProfessorId!=="") {
     91        try {
     92          const response = await axios.get(`http://192.168.0.29:8080/public/professor/${newOpinionTargetProfessorId}`, {withCredentials: true});
     93          let cyclicGraph = await response.data;
     94          var jsogStructure = JSOG.encode(cyclicGraph);
     95          cyclicGraph = JSOG.decode(jsogStructure);
     96          setNewOpinionTargetProfessor(cyclicGraph);
     97          setLoadedNewProfessor(true);
     98          setLoadingProf(false);
     99        } catch (error) {
     100          setFetchError(true);
     101        }
     102    }
     103  }
     104
     105  const[loadingSubj, setLoadingSubj] = useState(false);
     106
     107  const handleNewTargetSubjectChange = async (e) => {
     108    e.preventDefault();
     109    setLoadingSubj(true);
     110    if (newTargetSubjectId!=="") {
     111      try {
     112        const response = await axios.get(`http://192.168.0.29:8080/public/subject/${newTargetSubjectId}`, {withCredentials: true});
     113        let cyclicGraph = await response.data;
     114        var jsogStructure = JSOG.encode(cyclicGraph);
     115        cyclicGraph = JSOG.decode(jsogStructure);
     116        setNewTargetSubject(cyclicGraph);
     117        setLoadedNewSubject(true);
     118        setLoadingSubj(false);
     119      } catch (error) {
     120        setFetchError(true);
     121      }
     122    }
     123  }
     124
    68125  useEffect(() => {
    69     const url1 = `http://192.168.0.19:8080/secure/currentUser`;
    70     const url2 = `http://192.168.0.19:8080/secure/getAllPostReports`;
     126    const url1 = `http://192.168.0.29:8080/secure/currentUser`;
     127    const url2 = `http://192.168.0.29:8080/secure/getAllPostReports`;
    71128
    72129    const fetchUser = async () => {
     
    105162  // useEffect(() => {
    106163  //   const timer = setTimeout(() => {
    107   //     if (user === null) window.location.reload(false); <---- :-)
     164  //     if (user === null) window.location.reload(); <---- :-)
    108165  //   }, 3000);
    109166  //   return () => clearTimeout(timer);
     
    119176    try {
    120177      if(reportForModal.post !== null && reportForModal.post.targetProfessor !== undefined) {
    121         await axios(`http://192.168.0.19:8080/secure/updateOpinion/${reportForModal.post.postId}`,
     178        await axios(`http://192.168.0.29:8080/secure/updateOpinion/${reportForModal.post.postId}`,
    122179            {
    123180              method: "put",
     
    125182                newContent: newPostContent,
    126183                newTargetProfessorId: reportForModal.post.targetProfessor.professorId,
     184                newParentPostId: reportForModal.post.parent !== null ? reportForModal.post.parent.postId : "-1"
    127185              },
    128186              withCredentials: true,
    129187            })
    130         window.location.reload(false);
    131188      } else if(reportForModal.post !== null && reportForModal.post.targetProfessor === undefined) {
    132         await axios(`http://192.168.0.19:8080/secure/updateThread/${reportForModal.post.postId}`,
     189        await axios(`http://192.168.0.29:8080/secure/updateThread/${reportForModal.post.postId}`,
    133190            {
    134191              method: "put",
    135192              data: {
    136                 newTitle: newPostTitle,
     193                newTitle: newThreadTitle,
    137194                newContent: newPostContent,
    138                 newTargetSubjectId: reportForModal.post.targetSubject.subjectId
     195                newTargetSubjectId: reportForModal.post.targetSubject.subjectId,
     196                newParentThreadId: reportForModal.post.parent !== null ? reportForModal.post.parent.postId : "-1"
    139197              },
    140198              withCredentials: true,
    141199            })
    142         window.location.reload(false);
     200      }
     201        await axios(`http://192.168.0.29:8080/secure/markReportResolved/${reportForModal.postReportId}/${markResolved ? `resolve` : `open`}`,{
     202          method: "get",
     203          withCredentials: true
     204        })
     205    } catch (error) {
     206      setFetchError(true);
     207    }
     208    window.location.reload();
     209  }
     210
     211  const handleRelocate = async (e) => {
     212    e.preventDefault();
     213    try {
     214      if(reportForModal.post !== null && reportForModal.post.targetProfessor !== undefined) {
     215        var response = await axios(`http://192.168.0.29:8080/secure/updateOpinion/${reportForModal.post.postId}`,
     216            {
     217              method: "put",
     218              data: {
     219                newContent: reportForModal.post.content,
     220                newTargetProfessorId: newOpinionTargetProfessorId,
     221                newParentPostId: newParentPostId==="Постави како самостојно мислење" ? "-1" : newParentPostId //:)
     222              },
     223              withCredentials: true,
     224            })
     225      } else if(reportForModal.post !== null && reportForModal.post.targetProfessor === undefined) {
     226        var response = await axios(`http://192.168.0.29:8080/secure/updateThread/${reportForModal.post.postId}`,
     227            {
     228              method: "put",
     229              data: {
     230                newTitle: newThreadTitle,
     231                newContent: reportForModal.post.content,
     232                newTargetSubjectId: newTargetSubjectId,
     233                newParentThreadId: newParentThreadId==="Постави како самостојно мислење (нова тема)" ? "-1" : newParentThreadId //:)
     234              },
     235              withCredentials: true,
     236            })
     237      }
     238      await axios(`http://192.168.0.29:8080/secure/markReportResolved/${reportForModal.postReportId}/${markResolved ? `resolve` : `open`}`,{
     239        method: "get",
     240        withCredentials: true
     241      })
     242    } catch (error) {
     243      setFetchError(true);
     244    }
     245    setErrMsg(response.data);
     246    if (response.data==="") window.location.reload();
     247  }
     248
     249  const handleDelete = async (e) => {
     250    e.preventDefault();
     251    try {
     252      if(reportForModal.post !== null && reportForModal.post.targetProfessor !== undefined) {
     253        await axios(`http://192.168.0.29:8080/secure/deleteOpinion/${reportForModal.post.postId}`,
     254            {
     255              method: "delete",
     256              withCredentials: true,
     257            })
     258        window.location.reload();
     259      } else if(reportForModal.post !== null && reportForModal.post.targetProfessor === undefined) {
     260        await axios(`http://192.168.0.29:8080/secure/deleteThread/${reportForModal.post.postId}`,
     261            {
     262              method: "delete",
     263              withCredentials: true,
     264            })
    143265      }
    144266    } catch (error) {
    145267      setFetchError(true);
    146268    }
    147   }
    148 
    149   const handleDelete = (e) => {
    150     e.preventDefault();
     269    window.location.reload();
    151270  }
    152271
     
    181300      ) : (
    182301          <h3>Нема пријавени мислења</h3>
    183       ) : loadedUser && user.userRole==='MODERATOR' ? "се вчитува..." : ""}
     302      ) : loadedUser && user.userRole==='MODERATOR' ? <LoadingSpinner/> : ""}
    184303      <EntityUl style={{marginTop:"25px"}}>
    185304      {loadedPostReports && postReports.map((postReport) => {
     
    225344                  {dateConverter(
    226345                    new Date(post.timePosted).toString().slice(4, -43)
    227                   )}
     346                  )} <span style={{fontStyle:"normal",color:"blue"}}>#{post.postId}</span>
    228347                </OpinionCardContentTime>
    229348              </OpinionCardContent>
     
    287406                          {dateConverter(
    288407                              new Date(reportForModal.post.timePosted).toString().slice(4, -43)
    289                           )}
     408                          )} <span style={{fontStyle:"normal",color:"blue"}}>#{reportForModal.post.postId}</span>
    290409                        </OpinionCardContentTime>
    291410                      </OpinionCardContent>
     
    353472                  actionType === 0 ?
    354473              (<form onSubmit={e => handleEdit(e)}>
    355                 {reportForModal.post.title !== null && <label>
     474                {reportForModal.post.title !== null &&
     475                    <label>
    356476                  <b>Нов наслов на тема:</b>
    357477                  <ModalInput
    358                       value={newPostTitle}
    359                       onChange={e => setNewPostTitle(e.target.value)}
     478                      value={newThreadTitle}
     479                      onChange={e => setNewThreadTitle(e.target.value)}
    360480                      id="title"
    361481                      spellCheck={false}
     
    379499                  <input
    380500                      type="checkbox"
    381                       checked={markResolved}
    382501                      onChange={handleMarkResolved}
    383502                  />
     
    403522                          </form>)
    404523                          :
    405                           ("123")
    406                           : null
     524                          (reportForModal.post.targetProfessor !== undefined ?
     525                              (<form onSubmit={e => handleRelocate(e)}>
     526                                <p style={{color:"black"}}>Внеси <span style={{fontWeight:"bold"}}>ID</span> на секцијата за дискусија (за <span style={{fontWeight:"bold"}}>професор</span>)
     527                                    во која треба да биде преместено мислењето:</p>
     528                                    <div style={{marginTop:"15px"}}>
     529                                      <label>
     530                                        <ModalInput
     531                                            value={newOpinionTargetProfessorId}
     532                                            onChange={e => {e.preventDefault();setNewOpinionTargetProfessorId(e.target.value)}}
     533                                            id="newOpinionTargetProfessorId"
     534                                            spellCheck={false}
     535                                            style={{marginTop:"10px", marginBottom:"10px", width:"90px"}}
     536                                        />
     537                                        <button onClick={async (e) => {await handleNewTargetProfessorChange(e);}} style={{marginBottom:"10px", padding:"5px", fontFamily: "Roboto Mono, monospace"}}>Зачувај</button>
     538                                        {newOpinionTargetProfessor!==null && !loadingProf ? <p style={{color:"black", marginBottom:"20px", opacity:"50%"}}>Мислењето ќе се премести во секцијата за професорот со <span style={{fontWeight:"bold"}}>ID=
     539                                          {newOpinionTargetProfessor.professorId}</span> (<span style={{fontWeight:"bold"}}>{newOpinionTargetProfessor.professorName}</span>)</p> : loadingProf ? <LoadingSpinner style={{marginBottom:"15px", marginTop:"15px"}}/> : null}
     540                                        {newOpinionTargetProfessor && <p style={{color:"black", marginBottom:"10px"}}>Постави како дете на мислење со ID:</p>}
     541                                        {newOpinionTargetProfessor &&
     542                                        <select value={newParentPostId} onChange={e => setNewParentPostId(e.target.value)} style={{width:"280px", display:"block", padding:"5px",marginBottom:"5px", fontFamily: "Roboto Mono, monospace"}}>
     543                                          <option value="-1">Постави како самостојно мислење</option>
     544                                          {newOpinionTargetProfessor.relatedOpinions.filter((opinion)=>opinion.postId!==reportForModal.post.postId).map((opinion) => {
     545                                            return <option key={opinion.postId} value={opinion.postId}>{opinion.postId}</option>})
     546                                          }
     547                                        </select>}
     548                                        <br/>
     549                                        <input
     550                                            type="checkbox"
     551                                            defaultChecked={reportForModal.resolved}
     552                                            onChange={handleMarkResolved}
     553                                        />
     554                                        <span style={{marginLeft:"10px", fontWeight:"bold"}}>Означи како разрешено</span>
     555                                      </label>
     556                                    </div>
     557                                {errMsg!=="" && <p style={{color:"red", display:"flex", justifyContent:"space-around"}}>{errMsg}</p>}
     558                                    <ModalFooter type="submit">ПОТВРДИ</ModalFooter>
     559                                  </form>) :
     560                              //THREAD CASE
     561                              (<form onSubmit={e => handleRelocate(e)}>
     562                                <p style={{color:"black"}}>Внеси <span style={{fontWeight:"bold"}}>ID</span> на секцијата за дискусија (за <span style={{fontWeight:"bold"}}>предмет</span>)
     563                                  во која треба да биде преместено мислењето:</p>
     564                                <div style={{marginTop:"15px"}}>
     565                                  <label>
     566                                    <ModalInput
     567                                        value={newTargetSubjectId}
     568                                        onChange={e => {e.preventDefault();setNewTargetSubjectId(e.target.value)}}
     569                                        id="newTargetSubjectId"
     570                                        spellCheck={false}
     571                                        style={{marginTop:"10px", marginBottom:"10px", width:"90px"}}
     572                                    />
     573                                    <button onClick={async (e) => {await handleNewTargetSubjectChange(e);}} style={{marginBottom:"10px", padding:"5px", fontFamily: "Roboto Mono, monospace"}}>Зачувај</button>
     574                                    {newTargetSubject!==null && !loadingSubj ? <p style={{color:"black", marginBottom:"20px", opacity:"50%"}}>Мислењето ќе се премести во секцијата за предметот со <span style={{fontWeight:"bold"}}>ID=
     575                                      {newTargetSubject.subjectId}</span> (<span style={{fontWeight:"bold"}}>{newTargetSubject.subjectName}</span>)</p> : loadingSubj ? <LoadingSpinner style={{marginBottom:"15px", marginTop:"15px"}}/> : null}
     576                                    {newTargetSubject && <p style={{color:"black", marginBottom:"10px"}}>Постави како дете на мислење со ID:</p>}
     577                                    {newTargetSubject &&
     578                                        <select value={newParentThreadId} onChange={e => setNewParentThreadId(e.target.value)} style={{width:"370px", display:"block", padding:"5px",marginBottom:"5px", fontFamily: "Roboto Mono, monospace"}}>
     579                                          <option value="-1">Постави како самостојно мислење (нова тема)</option>
     580                                          {newTargetSubject.threads.filter((thread)=>thread.postId!==reportForModal.post.postId).map((thread) => {
     581                                            return <option key={thread.postId} value={thread.postId}>{thread.postId}</option>})
     582                                          }
     583                                        </select>}
     584                                    {newParentThreadId==="-1" && loadedNewSubject &&
     585                                        <>
     586                                        <p style={{marginTop:"10px"}}>Наслов на нова тема:</p>
     587                                      <ModalInput
     588                                        value={newThreadTitle}
     589                                        onChange={e => setNewThreadTitle(e.target.value)}
     590                                        id="titleChangeRelocate"
     591                                        spellCheck={false}
     592                                        style={{marginTop:"10px"}}
     593                                    />
     594                                    </>}
     595                                    <br/>
     596                                    <input
     597                                        type="checkbox"
     598                                        defaultChecked={reportForModal.resolved}
     599                                        onChange={handleMarkResolved}
     600                                    />
     601                                    <span style={{marginLeft:"10px", fontWeight:"bold"}}>Означи како разрешено</span>
     602                                  </label>
     603                                </div>
     604                                {errMsg!=="" && <p style={{color:"red", display:"flex", justifyContent:"space-around"}}>{errMsg}</p>}
     605                                <ModalFooter type="submit">ПОТВРДИ</ModalFooter>
     606                              </form>))
     607                  : null
    407608              }
    408609                </ModalBody>
     
    412613    </>
    413614  ) : (
    414     <>се вчитува...</>
     615      <LoadingSpinner/>
    415616  );
    416617}
  • reactapp/src/api/axios.js

    r3b6962d raf801e3  
    22
    33export default axios.create({
    4   baseURL: "http://192.168.0.19:8080",
     4  baseURL: "http://192.168.0.29:8080",
    55});
  • springapp/src/main/java/mk/profesori/springapp/Controller/PublicController.java

    r3b6962d raf801e3  
    2525@RestController
    2626@RequestMapping("/public")
    27 @CrossOrigin(origins = { "http://192.168.0.19:3000", "http://192.168.0.39:3000" })
     27@CrossOrigin(origins = { "http://192.168.0.29:3000", "http://192.168.0.28:3000" })
    2828public class PublicController {
    2929
  • springapp/src/main/java/mk/profesori/springapp/Controller/SecureController.java

    r3b6962d raf801e3  
    66import mk.profesori.springapp.Model.UserRole;
    77import mk.profesori.springapp.Service.CustomUserDetailsService;
     8import mk.profesori.springapp.Service.DisallowedOperationException;
     9import mk.profesori.springapp.Service.IncompatiblePostId;
    810import mk.profesori.springapp.Service.MainService;
    911import org.apache.tomcat.websocket.AuthenticationException;
     
    1820@RestController
    1921@RequestMapping("/secure")
    20 @CrossOrigin(origins = { "http://192.168.0.19:3000", "http://192.168.0.39:3000" })
     22@CrossOrigin(origins = { "http://192.168.0.29:3000", "http://192.168.0.28:3000" })
    2123public class SecureController {
    2224
     
    133135
    134136    @RequestMapping(value = "/updateOpinion/{postId}", method = RequestMethod.PUT)
    135     public void updateOpinion(@RequestBody ObjectNode objectNode, @PathVariable Long postId,
     137    public String updateOpinion(@RequestBody ObjectNode objectNode, @PathVariable Long postId,
    136138            @CurrentSecurityContext SecurityContext context) {
    137139        Authentication authentication = context.getAuthentication();
     
    140142            String newContent = objectNode.get("newContent").asText();
    141143            Long newTargetProfessorId = objectNode.get("newTargetProfessorId").asLong();
    142             mainService.updateOpinion(newContent, newTargetProfessorId, postId);
    143         }
     144            Long newParentPostId = objectNode.get("newParentPostId").asLong();
     145            try {
     146                mainService.updateOpinion(newContent, newTargetProfessorId, newParentPostId, postId);
     147            } catch (IncompatiblePostId | DisallowedOperationException e) {
     148                return e.getMessage();
     149            }
     150        }
     151
     152        return null;
    144153    }
    145154
    146155    @RequestMapping(value = "/updateThread/{postId}", method = RequestMethod.PUT)
    147     public void updateThread(@RequestBody ObjectNode objectNode, @PathVariable Long postId,
     156    public String updateThread(@RequestBody ObjectNode objectNode, @PathVariable Long postId,
    148157            @CurrentSecurityContext SecurityContext context) {
    149158        Authentication authentication = context.getAuthentication();
     
    153162            String newContent = objectNode.get("newContent").asText();
    154163            Long newTargetSubjectId = objectNode.get("newTargetSubjectId").asLong();
    155 
    156             if (objectNode.has("newParentThreadId")) {
    157                 Long newParentThreadId = objectNode.get("newParentThreadId").asLong();
     164            Long newParentThreadId = objectNode.get("newParentThreadId").asLong();
     165            try {
    158166                mainService.update_Thread(newTitle, newContent, newTargetSubjectId, newParentThreadId, postId);
    159             } else {
    160                 mainService.update_Thread(newTitle, newContent, newTargetSubjectId, null, postId);
     167            } catch (IncompatiblePostId | DisallowedOperationException e) {
     168                return e.getMessage();
    161169            }
    162170        }
     171
     172        return null;
    163173    }
    164174
     
    223233    }
    224234
    225     @RequestMapping(value = "/markReportResolved/{postReportId}/", method = RequestMethod.GET)
     235    @RequestMapping(value = "/markReportResolved/{postReportId}/{action}", method = RequestMethod.GET)
    226236    public void markReportResolved(@PathVariable Long postReportId, @PathVariable String action, @CurrentSecurityContext SecurityContext context) {
    227237        Authentication authentication = context.getAuthentication();
    228         if (authentication != null && authentication.getPrincipal() instanceof CustomUserDetails currentUser) {
     238        if (authentication != null && authentication.getPrincipal() instanceof CustomUserDetails currentUser &&
     239                currentUser.getUserRole().equals(UserRole.MODERATOR)) {
    229240            mainService.markReport(postReportId, action);
    230241        }
  • springapp/src/main/java/mk/profesori/springapp/Security/SecurityConfiguration.java

    r3b6962d raf801e3  
    3737            @Override
    3838            public void addCorsMappings(CorsRegistry registry) {
    39                 registry.addMapping("/**").allowedOrigins("http://192.168.0.19:3000", "http://192.168.0.39:3000")
     39                registry.addMapping("/**").allowedOrigins("http://192.168.0.29:3000", "http://192.168.0.28:3000")
    4040                        .allowCredentials(true);
    4141            }
  • springapp/src/main/java/mk/profesori/springapp/Service/MainService.java

    r3b6962d raf801e3  
    141141    public void addThread(String title, String content, Long subjectId, CustomUserDetails currentUser) {
    142142        Subject targetSubject = subjectRepository.findBySubjectId(subjectId);
    143 
    144         _Thread _threadToAdd = new _Thread(title, content, currentUser, null, null, null, targetSubject);
     143        String titleToSet = title.equals("") ? null : title;
     144
     145        _Thread _threadToAdd = new _Thread(titleToSet, content, currentUser, null, null, null, targetSubject);
    145146        _threadRepository.save(_threadToAdd);
    146147    }
     
    199200    public void delete_Thread(Long postId) {_threadRepository.deleteById(postId);}
    200201
    201     public void updateOpinion(String newContent, Long newTargetProfessorId, Long postId) {
     202    public String updateOpinion(String newContent, Long newTargetProfessorId, Long newParentPostId, Long postId) {
    202203        Opinion opinionToUpdate = opinionRepository.findByPostId(postId);
    203204
     
    205206
    206207        Professor newTargetProfessor = professorRepository.findByProfessorId(newTargetProfessorId);
    207         opinionToUpdate.setTargetProfessor(newTargetProfessor); //opcijava da ja dava samo kaj postovi so parentPost==null
     208        opinionToUpdate.setTargetProfessor(newTargetProfessor);
     209
     210        Opinion newParentOpinion = null;
     211        if (newParentPostId != -1) {
     212            newParentOpinion = opinionRepository.findByPostId(newParentPostId);
     213            if (!newParentOpinion.getTargetProfessor().equals(newTargetProfessor))
     214                throw new IncompatiblePostId("Мислењето не припаѓа во специфицираната секција за дискусија.");
     215            if (opinionToUpdate.getChildren().contains(newParentOpinion))
     216                throw new DisallowedOperationException("Мислењето не може да се постави како дете на негово дете (бесконечна рекурзија)");
     217        }
     218        opinionToUpdate.setParent(newParentOpinion);
     219
    208220        for(Post p : opinionToUpdate.getChildren()) {
    209221            Opinion o = (Opinion) p;
     
    212224        opinionToUpdate.setTimeLastEdited(LocalDateTime.now());
    213225        opinionRepository.save(opinionToUpdate);
    214     }
    215 
    216     public void update_Thread(String newTitle, String newContent, Long newTargetSubjectId, Long newParentThreadId, Long postId) {
     226        return null;
     227    }
     228
     229    public String update_Thread(String newTitle, String newContent, Long newTargetSubjectId, Long newParentThreadId, Long postId) {
    217230        _Thread _threadToUpdate = _threadRepository.findByPostId(postId);
    218231
     
    222235        _threadToUpdate.setTargetSubject(newTargetSubject);
    223236
    224         if(newParentThreadId != null) { //samo ako e specificirano
    225             _Thread newParentThread = _threadRepository.findByPostId(newParentThreadId);
    226 
    227             if (_threadToUpdate.getParent() == null || _threadToUpdate.getParent().getPostId().equals(postId)) {
    228                 _threadToUpdate.setParent(newParentThread);
    229             }//samo ako e naslovniot post ili directChild
    230             } else if(_threadToUpdate.getParent() != null) {
    231             _threadToUpdate.setParent(null);
    232             }
     237        _Thread newParentThread = null;
     238        if(newParentThreadId != -1) {
     239            newParentThread = _threadRepository.findByPostId(newParentThreadId);
     240            if (!newParentThread.getTargetSubject().equals(newTargetSubject))
     241                throw new IncompatiblePostId("Мислењето не припаѓа во специфицираната секција за дискусија.");
     242            if (_threadToUpdate.getChildren().contains(newParentThread))
     243                throw new DisallowedOperationException("Мислењето не може да се постави како дете на негово дете (бесконечна рекурзија)");
     244        }
     245        _threadToUpdate.setParent(newParentThread);
    233246
    234247            if(_threadToUpdate.getParent() == null) {
    235248             _threadToUpdate.setTitle(newTitle);
    236249            } else {
    237              _threadToUpdate.setTitle(null);
    238              }
     250                _threadToUpdate.setTitle(null);
     251            }
    239252
    240253         for(Post p : _threadToUpdate.getChildren()) {
     
    244257         _threadToUpdate.setTimeLastEdited(LocalDateTime.now());
    245258          _threadRepository.save(_threadToUpdate);
     259          return null;
    246260    }
    247261
     
    280294        if (action.equals("resolve")) report.setResolved(true);
    281295        else if (action.equals("open")) report.setResolved(false);
     296        postReportRepository.save(report);
    282297     }
    283298
  • springapp/src/main/java/mk/profesori/springapp/Service/RegistrationService.java

    r3b6962d raf801e3  
    4545                String tokenToResend = customUserDetailsService
    4646                        .createToken(userRepository.findByEmail(request.getEmail()).get());
    47                 String link = "http://192.168.0.19:8080/registration/confirm?token=" + tokenToResend;
     47                String link = "http://192.168.0.29:8080/registration/confirm?token=" + tokenToResend;
    4848                emailSender.send(request.getEmail(), emailSender.buildEmail(request.getUsername(), link));
    4949                return tokenToResend;
     
    6666                        UserRole.REGULAR));
    6767
    68         String link = "http://192.168.0.19:8080/registration/confirm?token=" + token;
     68        String link = "http://192.168.0.29:8080/registration/confirm?token=" + token;
    6969
    7070        emailSender.send(request.getEmail(), emailSender.buildEmail(request.getUsername(), link));
  • springapp/src/main/resources/application.properties

    r3b6962d raf801e3  
    1 spring.datasource.url=jdbc:postgresql://localhost:5432/profesori.mk
    2 spring.datasource.connectionProperties=useUnicode=true;characterEncoding=utf-8;
     1spring.datasource.url=jdbc:postgresql://localhost:5432/profesorimk
    32spring.datasource.username=postgres
    4 spring.datasource.password=1win7337
     3spring.datasource.password=baz@228
    54spring.jpa.hibernate.ddl-auto=update
    65spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
    76spring.jpa.show-sql=false
    87spring.jpa.properties.hibernate.format_sql=true
    9 server.address=192.168.0.19
     8server.address=192.168.0.29
    109spring.mail.host=localhost
    1110spring.mail.username=mailuser
Note: See TracChangeset for help on using the changeset viewer.