From 0dec13e0dce8bfc80cdfa1fa4c30d3f9fc1e9e0e Mon Sep 17 00:00:00 2001 From: Rushang Gajjal Date: Tue, 26 Mar 2019 00:59:47 +0530 Subject: [PATCH 1/5] Add files via upload --- dataset/priority.ipynb | 362 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 dataset/priority.ipynb diff --git a/dataset/priority.ipynb b/dataset/priority.ipynb new file mode 100644 index 0000000..9ab6008 --- /dev/null +++ b/dataset/priority.ipynb @@ -0,0 +1,362 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 106, + "metadata": {}, + "outputs": [], + "source": [ + "from gensim.models.doc2vec import Doc2Vec, TaggedDocument\n", + "from nltk.tokenize import word_tokenize\n", + "import csv\n", + "import re" + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "metadata": {}, + "outputs": [], + "source": [ + "stopwords = ['MON','TUE','WED','THU','FRI','SAT','SUN',\n", + " 'MONDAY','TUESDAY','WEDNESDAY','THURSDAY','FRIDAY','SATURDAY','SUNDAY',\n", + " 'JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC',\n", + " 'JANUARY','FEBRUARY','MARCH','APRIL','MAY','JUNE','JULY','AUGUST','SEPTEMBER','OCTOBER','NOVEMBER','DECEMBER']\n", + "def data():\n", + " #CSV data read\n", + " notams = []\n", + " with open('foreign.csv') as csv_file:\n", + " csv_reader = csv.reader(csv_file, delimiter=',')\n", + " for rows in csv_reader:\n", + " notams.append(rows)\n", + " \n", + " labels = set()\n", + " #data clean\n", + " for i in range(1,len(notams)):\n", + " notams[i][0] = re.sub(r'[^\\w\\s]','',notams[i][0])\n", + " notams[i][0] = notams[i][0].split('\\n')\n", + " lines = \"\"\n", + " for line in notams[i][0]:\n", + " if \"EAIP\" not in line:\n", + " lines += line\n", + " notams[i][0] = re.sub(\" +\",\" \",lines)\n", + " for sw in stopwords[:14:-1]:\n", + " notams[i][0] = re.sub(sw,\" DAYS \",notams[i][0])\n", + " for sw in stopwords[14::-1]:\n", + " notams[i][0] = re.sub(sw,\" MONTHS \",notams[i][0])\n", + " notams[i][1] = int(eval(notams[i][1]))\n", + " if notams[i][1]>2:\n", + " notams[i][1] = 2\n", + " elif notams[i][1]==2:\n", + " notams[i][1] = 1\n", + " else:\n", + " notams[i][1] = 0\n", + " notams[i][0] = re.sub(' +',' ',notams[i][0])\n", + " labels.add(notams[i][1])\n", + " \n", + " print(\"AL: LABELS:\", labels)\n", + " return notams" + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "AL: LABELS: {0, 1, 2}\n" + ] + }, + { + "data": { + "text/plain": [ + "['UTTI TWR OPR HR MONTHS MONTHS THS 05301300 MONTHS THS 05301130 MONTHS THS MONTHS THS CLSD',\n", + " 2]" + ] + }, + "execution_count": 108, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "notams = data()[1:]\n", + "notams[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[TaggedDocument(words=['caution', 'twr', 'lkpr', 'is', 'channel', 'with', 'days', 'arationmake', 'sure', 'about', 'the', 'correct', 'setting', 'on', 'radio', 'panel'], tags=['1']),\n", + " TaggedDocument(words=['due', 'to', 'unreliable', 'aftn', 'feed', 'from', 'pakistankabul', 'area', 'control', 'center', 'will', 'not', 'accept', 'anycoordination', 'information', 'via', 'the', 'aftn', 'system', 'fromthe', 'following', 'firs', 'lahore', 'control', 'karachi', 'controland', 'tehran', 'control', 'only', 'valid', 'method', 'of', 'coordinationwill', 'be', 'via', 'telephone', 'or', 'cellphone', 'communication', 'ufn'], tags=['1']),\n", + " TaggedDocument(words=['in', 'chart', 'standard', 'intrument', 'departure', 'page', 'ad', 'of', 'date', 'days', 'barcelona', 'gral', 'jose', 'antonio', 'anzoategui', 'intlrnav', 'gnss', 'arvex', 'rwy', 'sid', 'osamo', 'transition', 'is', 'suspended'], tags=['0']),\n", + " TaggedDocument(words=['wip', 'wi', 'rectangular', 'areapsn'], tags=['1']),\n", + " TaggedDocument(words=['rnav', 'rte', 'changedfm', 'trs', 'vordme', 'coord', 'tna', 'vordme', 'coord', 'hdg', 'and', 'dist', 'mntn', 'ref', 'aip', 'enr', 'enr', 'enr'], tags=['0'])]" + ] + }, + "execution_count": 109, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import re\n", + "def cleaners(tokens):\n", + " normalized = []\n", + " for token in tokens :\n", + " # remove digits + in range throw x>20 x<2\n", + " if 2<= len(token) <= 20 and not re.search(r'\\d', token):\n", + " normalized.append(token)\n", + " return normalized\n", + "\n", + "tagged_notams = [TaggedDocument(words=cleaners(word_tokenize(notam[0].lower())), tags=[str(notam[1])]) for notam in notams]\n", + "tagged_notams[-5:]" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/rusherrg/anaconda3/envs/tensorflow_gpuenv/lib/python3.6/site-packages/gensim/models/doc2vec.py:580: UserWarning: The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.\n", + " warnings.warn(\"The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.\")\n", + "/home/rusherrg/anaconda3/envs/tensorflow_gpuenv/lib/python3.6/site-packages/ipykernel_launcher.py:22: DeprecationWarning: Call to deprecated `iter` (Attribute will be removed in 4.0.0, use self.epochs instead).\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iteration 50\n", + "Doc2vec embeddings Model Saved\n" + ] + } + ], + "source": [ + "import sys, random\n", + "import multiprocessing\n", + "\n", + "n_notams = len(tagged_notams)\n", + "\n", + "# PARAMS\n", + "max_epochs = 50\n", + "vec_size = 250\n", + "min_count = 2\n", + "dm = 1 #0 CBOW / 1 DM\n", + "negative = 10\n", + "sample = 0 # drop freq threshold\n", + "alpha = 0.025\n", + "\n", + "model = Doc2Vec(size=vec_size,\n", + " min_count=min_count,\n", + " dm = dm,\n", + " negative = negative,\n", + " sample = sample,\n", + " workers=multiprocessing.cpu_count())\n", + "\n", + "update_train_epochs = model.iter\n", + "model.build_vocab(tagged_notams)\n", + "\n", + "for epoch in range(max_epochs):\n", + " sys.stdout.write('\\r' + 'iteration {0}'.format(epoch+1))\n", + " \n", + " random.shuffle(tagged_notams)\n", + " model.train(tagged_notams,\n", + " total_examples=n_notams,\n", + " epochs=update_train_epochs)\n", + " \n", + " # decrease the learning rate\n", + " model.alpha -= 0.002\n", + " # fix the learning rate, no decay\n", + " model.min_alpha = model.alpha\n", + "\n", + "d2v_filename = \"{epochs}Eps_{up_eps}UpEps_{dim}D_{dm}dm_{mc}mincount_{neg}neg_{sp}sample.d2vmodel\".format(epochs=max_epochs,\n", + " dim=vec_size,mc=min_count,\n", + " up_eps=update_train_epochs,\n", + " dm=dm,neg=negative,sp=sample,)\n", + "model.save(d2v_filename)\n", + "print(\"\\nDoc2vec embeddings Model Saved\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Manual Cosine Test Acc: 31.644049477602977\n" + ] + } + ], + "source": [ + "model= Doc2Vec.load(d2v_filename)\n", + "\n", + "\n", + "# Manual COSINE SIMILARITY tester ahead \n", + "from scipy import spatial\n", + "\n", + "'''\n", + "to find the vector of a document which is not in training data\n", + "test = 'PAPI RWY 32 IS RELOCATED AND REVISED GLIDE ANGLE/MEHT AS PER THE MENTIONED DETAILS PAPI RWY 32 LEFT/3.26DEG MEHT/66.71FT PAPI RWY 32 AT DIST OF 387M FM THR OF RWY 32'\n", + "test_data = cleaners(word_tokenize(test.lower()))\n", + "test_vector= model.infer_vector(test_data)\n", + "'''\n", + "\n", + "corr = 0\n", + "\n", + "for notam in notams:\n", + " test_vector = model.infer_vector(cleaners(word_tokenize(notam[0].lower())),steps=20)\n", + " preds = [max(0,1 - spatial.distance.cosine(test_vector, model.docvecs[str(i)])) for i in range(3)]\n", + "\n", + " if preds.index(max(preds)) == notam[1]:\n", + " corr += 1\n", + "\n", + "print(\"Manual Cosine Test Acc: \", corr*100/len(notams))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "model = Doc2Vec.load(d2v_filename)\n", + "\n", + "x_train = []\n", + "y_train = []\n", + "random.shuffle(notams)\n", + "\n", + "for notam in notams:\n", + " x_train.append(model.infer_vector(cleaners(word_tokenize(notam[0].lower())),steps=100))\n", + " \n", + " labels = \"PRIORITY_\"+str(notam[1])\n", + " y_train.append(labels)\n", + "\n", + "x_train = np.array(x_train)\n", + "y_train = np.array(y_train)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.metrics import accuracy_score, f1_score\n", + "import pickle\n", + "\n", + "print(\"N SAMPLES: \", len(x_train),len(y_train))\n", + "\n", + "SPLIT_RATIO = 0.9\n", + "n_tr = int(n_notams*SPLIT_RATIO)\n", + "n_te = n_notams - n_tr\n", + "\n", + "print(\"SPLITS: Train:{tr} | Test{te}\".format(tr=n_tr,te=n_te))\n", + "\n", + "X_train = x_train[:n_tr]*10\n", + "Y_train = y_train[:n_tr]\n", + "X_test = x_train[-n_tr:]*10\n", + "Y_test = y_train[-n_tr:]\n", + "\n", + "logreg_model = LogisticRegression(multi_class='multinomial', solver = 'lbfgs', max_iter = 200)\n", + "logreg_model.fit(X_train, Y_train)\n", + "\n", + "\n", + "train_acc = logreg_model.score(X_train, Y_train)*100\n", + "test_acc = logreg_model.score(X_test, Y_test)*100\n", + "\n", + "print(\"TRAIN ACC: \",train_acc)\n", + "print(\"TEST ACC: \",test_acc)\n", + "\n", + "# Example test item\n", + "for i in range(3):\n", + " pick = random.randint(0,n_te)\n", + " print(pick)\n", + " print(logreg_model.predict([X_test[pick]]))\n", + " print(notams[n_te+pick])\n", + "\n", + "y_preds = logreg_model.predict(X_test)\n", + "print('Testing accuracy %s' % accuracy_score(Y_test, y_preds))\n", + "print('Testing F1 score: {}'.format(f1_score(Y_test, y_preds, average='weighted')))\n", + "\n", + "model_labels = {}\n", + "for i in range(len(y_preds)):\n", + " diff = abs(int(y_preds[i][-1]) - int(Y_test[i][-1]))\n", + " try:\n", + " model_labels[diff]\n", + " except:\n", + " model_labels[diff] = 1\n", + " else:\n", + " model_labels[diff] += 1\n", + "print(model_labels)\n", + "\n", + "# SAVER\n", + "filename = \"{train_ac}TRA_{test_ac}TEA.model\".format(train_ac=int(train_acc),test_ac=int(test_acc))\n", + "\n", + "pickle.dump(logreg_model, open(filename, 'wb'))\n", + "print(\"Model Saved!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "test = '''PAPI RWY 32 IS RELOCATED AND REVISED GLIDE ANGLE/MEHT AS PER THE MENTIONED DETAILS PAPI RWY 32 LEFT/3.26DEG MEHT/66.71FT PAPI RWY 32 AT DIST OF 387M FM THR OF RWY 32'''\n", + "test = re.sub(r'[^\\w\\s]','',test)\n", + "test = \" \".join(test.split('\\n'))\n", + "lines = \"\"\n", + "for line in test:\n", + " if \"EAIP\" not in line:\n", + " lines += line\n", + "test = re.sub(\" +\",\" \",lines)\n", + "for sw in stopwords[::-1]:\n", + " test = re.sub(sw,\" \",test)\n", + "test = re.sub(' +',' ',test)\n", + "print(cleaners(word_tokenize(test.lower())))\n", + "print(logreg_model.predict([model.infer_vector(cleaners(word_tokenize(test.lower())),steps=1000)]))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 29dc08aded7b8f10a8428e70018f4dbf321efb07 Mon Sep 17 00:00:00 2001 From: Hetal Kuvadia Date: Wed, 27 Mar 2019 08:39:00 +0530 Subject: [PATCH 2/5] Delete pass.jpeg --- webapp/app/static/js/imports/pass.jpeg | Bin 50881 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 webapp/app/static/js/imports/pass.jpeg diff --git a/webapp/app/static/js/imports/pass.jpeg b/webapp/app/static/js/imports/pass.jpeg deleted file mode 100644 index 44eb2d3e3ae88adabaf3a924df034d4c3958ffe0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50881 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 Date: Fri, 17 May 2019 10:51:08 +0530 Subject: [PATCH 3/5] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e28e76..55d7879 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ - [@Korusuke](https://github.com/Korusuke) - [@Rusherrg](https://github.com/RusherRG) - [@hetzz](https://github.com/hetzz) -- [@aditya1999](https://github.com/aditya1999) +- [@Syn3rman](https://github.com/Syn3rman) - [@akshay-99](https://github.com/akshay-99) - [@aviiiij](https://github.com/aviiij) From 2e8cb9e054ef5fa90455f92d84c0ee522a178d4f Mon Sep 17 00:00:00 2001 From: RusherRG Date: Mon, 27 Apr 2020 20:36:41 +0530 Subject: [PATCH 4/5] Update and dockerize --- webapp/Dockerfile | 15 ++++ webapp/app/views.py | 153 ++++++++++++++++++++++++---------------- webapp/requirements.txt | 2 + 3 files changed, 108 insertions(+), 62 deletions(-) create mode 100644 webapp/Dockerfile diff --git a/webapp/Dockerfile b/webapp/Dockerfile new file mode 100644 index 0000000..89131da --- /dev/null +++ b/webapp/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.6-alpine + +ENV FLASK_SECRET_KEY=trewqyuio + +RUN mkdir /app +WORKDIR /app + +COPY requirements.txt /app/ +RUN pip install --no-cache-dir -r requirements.txt + +COPY . /app + +EXPOSE 5000 + +CMD ["gunicorn", "--chdir", "/app", "run:app", "-b", "0.0.0.0:5000"] diff --git a/webapp/app/views.py b/webapp/app/views.py index 39f6ee0..c7279e5 100644 --- a/webapp/app/views.py +++ b/webapp/app/views.py @@ -1,6 +1,8 @@ # views.py -from flask import render_template,request,Response,redirect,url_for,session,jsonify -import json,os,datetime +from flask import render_template, request, Response, redirect, url_for, session, jsonify +import json +import os +import datetime from app import app from app import extract from app import database @@ -8,19 +10,20 @@ from pprint import pprint from datetime import datetime import random -import smtplib, ssl +import smtplib +import ssl #import overpy # app.secret_key = "WORKS" app.secret_key = os.environ['FLASK_SECRET_KEY'] -#URL Routes +# URL Routes # @app.route('/') # def index(): # print("INDEX") # session['username'] = {} -# return render_template("login.html") +# return render_template("login.html") @app.route('/') @app.route('/dashboard') @@ -29,97 +32,106 @@ def dashboard(): facility = database.get_notams('facility') print(airspace, facility) for i in range(len(airspace)): - airspace[i]['msg'] = airspace[i]['msg'].replace('\n','
') + airspace[i]['msg'] = airspace[i]['msg'].replace('\n', '
') for i in range(len(facility)): - facility[i]['msg'] = facility[i]['msg'].replace('\n','
') + facility[i]['msg'] = facility[i]['msg'].replace('\n', '
') print(airspace, facility) if session.get('verification_code'): vcs = True else: vcs = False - return render_template("dashboard_v2/newdash.html", facility = facility , airspace = airspace, logged_in = check_login(), vcs=vcs) + return render_template("dashboard_v2/newdash.html", facility=facility, airspace=airspace, logged_in=check_login(), vcs=vcs) + @app.route('/admin_airspace') def admin_airspace(): try: - if session['username']['admin']!=True: + if session['username']['admin'] != True: return redirect(url_for('dashboard')) except: return redirect(url_for('dashboard')) else: notam = {'class': 'Notam Series', 'airport': '', 'notam': '', 'start_date': 'Start Date', - 'end_date': 'End Date', 'start_time': 'Start Time', 'end_time': 'End Time', - 'notam_no':''} - return render_template("dashboard_v2/index.html",notam=notam) + 'end_date': 'End Date', 'start_time': 'Start Time', 'end_time': 'End Time', + 'notam_no': ''} + return render_template("dashboard_v2/index.html", notam=notam) + @app.route('/admin_facility') def admin_facility(): try: - if session['username']['admin']!=True: + if session['username']['admin'] != True: return redirect(url_for('dashboard')) except: return redirect(url_for('dashboard')) else: notam = {'class': 'Notam Series', 'airport': '', 'notam': '', 'start_date': 'Start Date', - 'end_date': 'End Date', 'start_time': 'Start Time', 'end_time': 'End Time', - 'notam_no':''} - return render_template("dashboard_v2/Facility.html",notam=notam) + 'end_date': 'End Date', 'start_time': 'Start Time', 'end_time': 'End Time', + 'notam_no': ''} + return render_template("dashboard_v2/Facility.html", notam=notam) - -#Request Routes +# Request Routes @app.route('/processor', methods=['POST']) def processor(): return Response( - json.dumps( - extract.extract('NOTAM.pdf') - ), mimetype='application/json' - ) + json.dumps( + extract.extract('NOTAM.pdf') + ), mimetype='application/json' + ) + -@app.route('/create_notam',methods=['POST']) +@app.route('/create_notam', methods=['POST']) def create(): notam = {} data = request.get_json() print(data) if data['notam_type'] == 'airspace': - keys = ['notam_notam', 'notam_series', 'notam_no', 'fir', 'scenario', 'nature', - 'latin', 'longin', 'stime', 'etime', 'remarks', 'map_poly', 'zoom', 'llimit', 'ulimit','notam_type'] + keys = ['notam_notam', 'notam_series', 'notam_no', 'fir', 'scenario', 'nature', + 'latin', 'longin', 'stime', 'etime', 'remarks', 'map_poly', 'zoom', 'llimit', 'ulimit', 'notam_type'] else: keys = ['notam_series', 'notam_no', 'fir', 'ident', 'freq', 'latin', 'longin', 'stime', 'etime', 'remarks', 'map_poly', 'zoom', 'notam_type'] notam_data = "" if data.get('notam_notam'): - data['msg']=data['notam_notam'] + data['msg'] = data['notam_notam'] else: msg = '' - msg+=data['notam_series']+data['notam_no']+'/'+'19'+' NOTAMN\n' + msg += data['notam_series']+data['notam_no']+'/'+'19'+' NOTAMN\n' msg += 'Q) '+data['fir']+'\n' - msg+='A) '+data['fir']+' B) '+data['stime'].replace('/', '').replace(' ', '').replace(':', '')+' C) '+data['etime'].replace('/', '').replace(' ', '').replace(':', '')+'\n' + msg += 'A) '+data['fir']+' B) '+data['stime'].replace('/', '').replace(' ', '').replace( + ':', '')+' C) '+data['etime'].replace('/', '').replace(' ', '').replace(':', '')+'\n' try: - coords = 'AROUND '+str(round(float(data['latin'])*10000, 2))+'N'+' '+str(round(float(data['longin'])*10000, 2)) + coords = 'AROUND ' + \ + str(round(float(data['latin'])*10000, 2))+'N' + \ + ' '+str(round(float(data['longin'])*10000, 2)) except: try: coords = 'WITHIN THE REGION ' if data['map_poly'][0]: - coords += "CENTERED AT "+str(0.000539957*data['map_poly'][0][0]) + " " +str(0.000539957*data['map_poly'][0][0]) + " RADIUS " + str(0.000539957*data['map_poly'][1]) + coords += "CENTERED AT "+str(0.000539957*data['map_poly'][0][0]) + " " + str( + 0.000539957*data['map_poly'][0][0]) + " RADIUS " + str(0.000539957*data['map_poly'][1]) coords += '\n' for i in data['map_poly'][2][0]: - coords += 'lat : ' + str(i['lat']) + " lng : " + str(i['lng'])+"\n" + coords += 'lat : ' + \ + str(i['lat']) + " lng : " + str(i['lng'])+"\n" except: coords = '' - msg+='E) '+(' AIRSPACE ' if data['notam_type']=='airspace' else 'FACILITY ')+data.get('scenario', '')+' DUE '+data.get('nature', '')+' '+coords+'\n' - msg+=data.get('remarks', '')+'\n ' + msg += 'E) '+(' AIRSPACE ' if data['notam_type'] == 'airspace' else 'FACILITY ')+data.get( + 'scenario', '')+' DUE '+data.get('nature', '')+' '+coords+'\n' + msg += data.get('remarks', '')+'\n ' nw = datetime.utcnow() - msg+='Created On: '+str(nw.year)+'/'+str(nw.month)+'/'+str(nw.day)+' '+str(nw.hour)+':'+str(nw.minute) - data['msg']=msg + msg += 'Created On: '+str(nw.year)+'/'+str(nw.month) + \ + '/'+str(nw.day)+' '+str(nw.hour)+':'+str(nw.minute) + data['msg'] = msg keys.append('msg') for key in keys: notam[key] = data[key] # notam_data += " " + notam[key] notam['coords'] = [] - notam['coords'].append((notam['latin'],notam['longin'])) + notam['coords'].append((notam['latin'], notam['longin'])) # notam_extract = extract.extract_is_back(notam_data['notam_notam']) notam['issued_by'] = "Administrator" @@ -131,12 +143,13 @@ def create(): else: return json.dumps({'success': "NOTAM Exists"}), 200, {'ContentType': 'application/json'} -@app.route('/signup',methods=['POST']) + +@app.route('/signup', methods=['POST']) def signup(): user = request.form user = user.to_dict(flat=False) for key in user.keys(): - user[key] = user[key][0] + user[key] = user[key][0] if user['secretKey'] == os.environ['secretKey']: user['admin'] = True else: @@ -145,11 +158,13 @@ def signup(): return redirect(url_for('dashboard')) return redirect(url_for('dashboard')) + @app.route('/sign_up') def sign_up(): return render_template("login.html") -@app.route('/verify_login',methods=['POST']) + +@app.route('/verify_login', methods=['POST']) def verify_login(): user = request.form user = user.to_dict(flat=False) @@ -159,7 +174,7 @@ def verify_login(): if 'verificode' in user and session.get('verification_code'): if user['verificode'][0] == session['verification_code']: print("LOGIN SUCCESSFUL") - session['username'] = session['username_temp'] + session['username'] = session['username_temp'] session.pop('verification_code', None) print(session['username']) return redirect(url_for('dashboard')) @@ -171,14 +186,15 @@ def verify_login(): if user: vcode = '' for i in range(6): - vcode+=str(random.randint(0, 9)) - session['verification_code']=vcode - sendemail(user['email'],vcode) - session['username_temp'] = {'user_name':user['email'],'admin':user['admin'], "key":app.secret_key} + vcode += str(random.randint(0, 9)) + session['verification_code'] = vcode + sendemail(user['email'], vcode) + session['username_temp'] = { + 'user_name': user['email'], 'admin': user['admin'], "key": app.secret_key} return redirect(url_for('dashboard')) + def sendemail(rec, vc): - port = 465 # For SSL smtp_server = "smtp.gmail.com" @@ -198,27 +214,30 @@ def sendemail(rec, vc): except: pass + @app.route('/getnotamdata') def getnotamdata(): notam_no = request.args.get('notamid') - notam = database.get_notam('notam_no',notam_no) - notam['_id']='hi' + notam = database.get_notam('notam_no', notam_no) + notam['_id'] = 'hi' return jsonify(notam) -@app.route('/editnotam',methods=['POST']) + +@app.route('/editnotam', methods=['POST']) def edit_notam(): notam_no = request.args.get('notamid') - notam = database.get_notam('notam_no',notam_no) - notam['_id']='hi' + notam = database.get_notam('notam_no', notam_no) + notam['_id'] = 'hi' return jsonify(notam) - + @app.route('/deletenotam') def deletenotam(): notam_no = request.args.get('notamid') - result = database.remove_notam('notam_no',notam_no) + result = database.remove_notam('notam_no', notam_no) return result + @app.route('/predict_notam', methods=["GET"]) def predict_notam(): notam = request.args.get('notam') @@ -231,22 +250,26 @@ def predict_notam(): else: return render_template('dashboard_v2/index.html', notam=notam) + def check_login(): #print(request, type(request)) try: - if(session['username']['admin']==True): + if(session['username']['admin'] == True): return True else: return False except: return False + def overpass_aerodrome(query): pass + def overpass_runway(query): pass + def overpass_taxiway(coords): api = overpy.Overpass() q = """ @@ -263,34 +286,37 @@ def overpass_taxiway(coords): nod = [] for node in way.nodes: print("Lat: %f,Lon: %f" % (node.lat, node.lon)) - nod.append([node.lat,node.lon]) + nod.append([node.lat, node.lon]) res[way.tags.get("name", "n/a")] = nod return res - + @app.route('/logout') def logout(): - session['username']=None - return redirect(url_for('dashboard')) + session['username'] = None + return redirect(url_for('dashboard')) -#DEBUG URLs +# DEBUG URLs @app.route('/visualizer') def visualizer(): return render_template("visualizer/visual.html") + @app.route('/populate') def populate_notams(): database.populate() return redirect(url_for('dashboard')) -@app.route('/listview') + +@app.route('/listview') def listview(): return render_template("index.html") + @app.route('/admin1') def admin1(): try: - if session['username']['admin']!=True: + if session['username']['admin'] != True: return redirect(url_for('index')) except: return redirect(url_for('index')) @@ -298,17 +324,20 @@ def admin1(): facility = database.get_notams('facility') return render_template('admin.html', facility=facility, airspace=airspace) + @app.route('/dashboard2') def dashboard2(): airspace = database.get_notams('airspace') facility = database.get_notams('facility') print(airspace, facility) - return render_template("dashboard.html", facility = facility , airspace = airspace) + return render_template("dashboard.html", facility=facility, airspace=airspace) + @app.route('/kittu') def kittu(): return render_template("kittu.html") + @app.route('/test') def test(): tnot = '''A0422/19 NOTAMN @@ -325,7 +354,7 @@ def test(): F) GND G) FL140''' return str(extract.extract_is_back(tnot)) + @app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404 - diff --git a/webapp/requirements.txt b/webapp/requirements.txt index 6f02fb6..ebad290 100644 --- a/webapp/requirements.txt +++ b/webapp/requirements.txt @@ -4,3 +4,5 @@ itsdangerous==1.1.0 Jinja2==2.10 MarkupSafe==1.1.0 Werkzeug==0.14.1 +pymongo +gunicorn From dd9c1233ae5321c1f3a64ebc82addca0622fb595 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2020 15:07:23 +0000 Subject: [PATCH 5/5] Bump werkzeug from 0.14.1 to 0.15.3 in /webapp Bumps [werkzeug](https://github.com/pallets/werkzeug) from 0.14.1 to 0.15.3. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/master/CHANGES.rst) - [Commits](https://github.com/pallets/werkzeug/compare/0.14.1...0.15.3) Signed-off-by: dependabot[bot] --- webapp/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/requirements.txt b/webapp/requirements.txt index ebad290..5382c5a 100644 --- a/webapp/requirements.txt +++ b/webapp/requirements.txt @@ -3,6 +3,6 @@ Flask==1.0.2 itsdangerous==1.1.0 Jinja2==2.10 MarkupSafe==1.1.0 -Werkzeug==0.14.1 +Werkzeug==0.15.3 pymongo gunicorn