diff --git a/README.md b/README.md index 8068dce..cb08a77 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ + +CELCOMBiller +============ + +CELCOMBiller is an open source biller system to *OpenBTS* and *Asterisk* + + + # Used third-party libraries * pyst @@ -10,7 +18,7 @@ ```bash $ virtualenv -p /usr/bin/python2.7 venv $ source venv/bin/activate -$ pip install --allow-external pyst --allow-unverified pyst -r requirements.txt +$ pip install --allow-external --allow-unverified -r requirements.txt ``` ## Database setup @@ -21,13 +29,14 @@ Each SIP user must be inserted in the database of users with a balance. The pyth from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy from config import db -from models import User +from models import User, Ballance -admin = User('admin', 'adm123', '999999999', '9999', True) -guest = User('guest', '123123', '999999999', '0000', False) +admin = User(True,'administrator', 'nowhere', '000','admin', 'adm123', '999999999','999999999999999', '0' ,'0') +guest = User(True,'guest', 'nowhere', '1','guest', '123123', '999999998','999999999999998', '0' ,'0') db.session.add(admin) db.session.add(guest) + db.session.commit() ``` @@ -41,7 +50,7 @@ To test the api we will use curl ###USER -login is required to test: +you must login before test the api: ```bash curl -c cookiefile -d "username=admin&password=adm123" -X POST -s http://localhost:5000/login @@ -50,25 +59,31 @@ curl -c cookiefile -d "username=admin&password=adm123" -X POST -s http://localho now to add user: ```bash -curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"username":"yourusername","password":"yourpassword","clid":"999999999","imsi":"12345678900" "admin":'false'}' -s http://localhost:5000/api/users +curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"username":"yourusername","password":"yourpassword","clid":"999999999","imsi":"12345678900", "admin":'false', "name":"administrator","adress":"lasse","cpf":"000","voice_balance":"0","data_balance":"0"}' -s http://localhost:5000/api/users ``` the balance came by another table, so we want add balance to user we need run: -add balance: +add/remove data balance: ```bash -curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"signal":"+", "type_":"increase", "value": "1000", "userId":1}' -s http://localhost:5000/api/balance +curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"value": "1000", "user_id":3,"origin":"web"}' -s http://localhost:5000/api/data_balance + #note that userId need some user id, in that case we use 1 +#to remove balance the value must be negative ``` -remove balance: +add/remove voice balance: ```bash -curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"signal":"+", "type_":"increase", "value": "1000", "userId":1}' -s http://localhost:5000/api/balance +curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"value": "1000", "userId":1}' -s http://localhost:5000/api/voice_balance + +#note that userId need some user id, in that case we use 1 +#to remove balance the value must be negative ``` + update user ```bash @@ -81,18 +96,18 @@ remove user curl -X DELETE -s http://localhost:5000/api/users/yourusername -b cookiefile ``` -###GROUPS +###Schedule add group ```bash -curl -X POST -H "Content-Type: application/json" -d '{"name":"group_name","day":1, "month":1, "year":3000, "count":10, "users":[id_]}' -s http://localhost:5000/api/groups +curl -X POST -H "Content-Type: application/json" -d '{"name":"group_name","day":1, "month":1, "year":3000, "count":10}' -s http://localhost:5000/api/schedules ``` update group ```bash -curl -X PATCH -H "Content-Type: application/json" -d '{}' -s http://localost:5000/api/groups/group_name +curl -X PATCH -H "Content-Type: application/json" -d '{}' -s http://localost:5000/api/schedules/schedule ``` @@ -145,25 +160,7 @@ celcombiller_reducer ``` +## Upstart - -You dont need to write a constructor, you can either treat the addresses property on a Person instance as a list: - -a = Address(email='foo@bar.com') -p = Person(name='foo') -p.addresses.append(a) - -Or you can pass a list of addresses to the Person constructor - -a = Address(email='foo@bar.com') -p = Person(name='foo', addresses=[a]) - -In either case you can then access the addresses on your Person instance like so: - -db.session.add(p) -db.session.add(a) -db.session.commit() -print p.addresses.count() # 1 -print p.addresses[0] #
-print p.addresses.filter_by(email='foo@bar.com').count() # 1 +To have Celcombiler running as a service you have to modify the file celcombiller.conf and put it in your /etc/init directory. diff --git a/adduser.py b/adduser.py index f6341ac..392ca9c 100644 --- a/adduser.py +++ b/adduser.py @@ -1,11 +1,13 @@ -from flask import Flask -from flask.ext.sqlalchemy import SQLAlchemy from config import db -from models import User, Ballance +from models import User -admin = User('admin', 'adm123', '999999999', True,'999999999999999') -guest = User('guest', '123123', '999999998', False,'000000000000000') + +admin = User('0', 'administrator', '000', 'admin', 'adm123', + '999999999', '999999999999999', '0', '0', 'nowhere') +guest = User('3', 'guest', '1', 'guest', '123123', '999999998', + '999999999999998', '0', '0', 'nowhere') db.session.add(admin) db.session.add(guest) + db.session.commit() diff --git a/app.py b/app.py old mode 100644 new mode 100755 index 2308a3b..10b4335 --- a/app.py +++ b/app.py @@ -1,27 +1,37 @@ import flask -from flask import Flask, session, request, flash, url_for, redirect, \ - render_template, abort +from flask import request, flash, render_template from config import db, app, login_manager -from models import CDR, User, Groups, Dates, Ballance -from time import strftime +from models import User, VoiceBalance, DataBalance, Schedules, ScheduleInput, \ + ScheduleUser from datetime import * from dateutil.rrule import * from dateutil.parser import * from dateutil.relativedelta import * from flask_restless import ProcessingException -from flask.ext.login import login_user , logout_user , current_user ,\ +from flask.ext.login import login_user, logout_user, current_user,\ login_required import json from openbts import to_openbts + @app.route('/') def index(): """ Index page, just show the logged username """ - return render_template('index.html') + try: + if current_user.is_authenticated(): + return render_template('index.html') + else: + return "no else" + except Exception: + return render_template('anonymous.html') +@app.route('/test',methods=['GET']) +def test(): + return "rodou" +# Login, if the user does not exist it returs a error page @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'GET': @@ -34,68 +44,105 @@ def login(): if registered_user is None: flash('Username or Password is invalid', 'error') return render_template('ERROR.html') - login_user(registered_user) - json_with_names = check_time() - return "Hello, cross-origin-world!" - -def check_time(): - if not current_user.is_admin(): - return False - else: - json_need_update = [] - groups = Groups.query.all() - for group in groups: - boolean_time = (group.dates_to_update[0].date - datetime.now())\ - .total_seconds() - boolean_time = 1 if boolean_time < 0 else 0 - if boolean_time == 1: - json_need_update.append(group.name) - if json_need_update == []: - return None + if login_user(registered_user): + return "Hello, cross-origin-world!" else: - return json_need_update + flash('Flask Login error', 'error') + return render_template('ERROR.html') + # json_with_names = check_time() -def already_has_group(data=None, **kargs): +# Returns the user data balance +@app.route('/check_data_balance', methods=['GET', 'POST']) +def check_data_balance(*args, **kargs): data = request.data request_body = json.loads(data) - group = Groups.query.\ - filter_by(name=request_body['name']).first() - if group is not None: - raise ProcessingException(description='Already has this Group', code=400) - else: - pass + # Is it a better way to handle the exception when the user is not found ? + try: + x = User.query.filter_by( + imsi=request_body['imsi']).first().DataBalance() + return str(x) + except AttributeError: + return "none" + +# Returns the user voice balance -def put_user_id_in_buffer(*args, **kargs): - data = request.data - request_body = json.loads(data) - global buffer_usersId - buffer_usersId = request_body['users'] - del kargs['data']['users'] -def add_users_to_group(*args, **kargs): - global buffer_usersId +@app.route('/check_voice_balance', methods=['GET', 'POST']) +def check_voice_balance(*args, **kargs): data = request.data request_body = json.loads(data) - group = Groups.query\ - .filter_by(name=request_body['name']).first() - for userId in buffer_usersId: - user = User.query.filter_by(id_=userId).first() - group.tunel.append(user) - db.session.add(group) - db.session.commit() - pass - -def add_dates_to_group(*args, **kargs): - global data_count + # Is it a better way to handle the exception when the user is not found ? + try: + x = User.query.filter_by( + imsi=request_body['imsi']).first().VoiceBalance() + return str(x) + except AttributeError: + return "none" + + +# I dont know what this function does so I commented it. +# def check_time(): +# if not current_user.is_admin(): +# return False +# else: +# json_need_update = [] +# schedules = Schedules.query.all() +# for schedule in schedules: +# boolean_time = (schedule.dates_to_update[0].date - datetime.now())\ +# .total_seconds() +# boolean_time = 1 if boolean_time < 0 else 0 +# if boolean_time == 1: +# json_need_update.append(schedule.name) +# if json_need_update == []: +# return None +# else: +# return json_need_update + +# Check if the user has a schedule +def schedule_exists(data=None, **kargs): data = request.data request_body = json.loads(data) - group = Groups.query.\ + schedule = Schedules.query.\ filter_by(name=request_body['name']).first() - listOfdates = Dates.query.order_by(Dates.id_.desc()).limit(data_count) - for date in listOfdates: - group.dates_to_update.append(date) - pass + if schedule is not None: + raise ProcessingException( + description='A schedule with this name already exists', code=400) + else: + pass + +# Let's put onlt one user at time in the schedule +# def put_user__idin_buffer(*args, **kargs): +# data = request.data +# request_body = json.loads(data) +# global buffer_users_id +# buffer_users_id = request_body['users'] +# del kargs['data']['users'] + +# def add_users_to_schedule(*args, **kargs): +# global buffer_users_id +# data = request.data +# request_body = json.loads(data) +# schedule = Schedules.query\ +# .filter_by(name=request_body['name']).first() +# #for user_id in buffer_users_id: +# user = User.query.filter_by(_id=user_id).first() +# schedule.tunel.append(user) +# db.session.add(schedule) +# db.session.commit() +# pass + +# def add_dates_to_schedule(*args, **kargs): +# global data_count +# data = request.data +# request_body = json.loads(data) +# schedule = Schedules.query.\ +# filter_by(name=request_body['name']).first() +# listOfdates = Dates.query.order_by(Dates._id.desc()).limit(data_count) +# for date in listOfdates: +# schedule.dates_to_update.append(date) +# pass + def transform_to_utc(*args, **kargs): global data_count @@ -110,7 +157,7 @@ def transform_to_utc(*args, **kargs): month = int(request_body['month']) how_many = int(request_body['count']) if year < min_year or ((month < min_month) and (year <= min_year)) or \ - (day < min_day and (month <= min_month and year <= min_year)): + (day < min_day and (month <= min_month and year <= min_year)): raise ProcessingException(description='Date not accept', code=400) else: del kargs['data']['day'] @@ -125,22 +172,42 @@ def transform_to_utc(*args, **kargs): db.session.commit() pass -def date_now(*args, **kargs): - kargs['data']['date'] = unicode(datetime.now()) - global buffer_usersId - buffer_usersId = kargs['data']['userId'] - del kargs['data']['userId'] +# def date_now(*args, **kargs): +# kargs['data']['date'] = unicode(datetime.now()) +# global buffer_users_id +# buffer_users_id = kargs['data']['user_id'] +# #del kargs['data']['user_id'] + -def add_user_balance(*args, **kargs): - global buffer_usersId +def add_user_data_balance(*args, **kargs): + global buffer_users_id data = request.data request_body = json.loads(data) - request_body['userId'] - x = Ballance.query.order_by(Ballance.id_.desc()).first() - x.usersId = request_body['userId'] + # Check if we are passing the user id or the imsi in the user_id field, it + # is necessary because Openbts users IMSI only. + if request_body['user_id'] < 1e13: + x = DataBalance.query.order_by(DataBalance._id.desc()).first() + x.users_id = request_body['user_id'] + else: + x = DataBalance.query.order_by(Balance._id.desc()).first() + x.users_id = User.query.filter_by( + imsi=request_body['user_id']).first()._id db.session.add(x) db.session.commit() + +def add_user_voice_balance(*args, **kargs): + global buffer_users_id + data = request.data + request_body = json.loads(data) + + x = VoiceBalance.query.order_by(VoiceBalance._id.desc()).first() + x.users_id = request_body['from_user_id'] + + db.session.add(x) + db.session.commit() + + @app.route('/logout') def logout(): logout_user() @@ -148,8 +215,8 @@ def logout(): @login_manager.user_loader -def load_user(id_): - return User.query.get(int(id_)) +def load_user(_id): + return User.query.get(int(_id)) @app.route('/check') @@ -161,23 +228,33 @@ def check_login(): return render_template('check.html') +@app.route('/checkadm') +def checkadm(): + """ + Index page, just show the logged username + """ + + return str(current_user) + + def auth(*args, **kargs): """ Required API request to be authenticated """ - if not current_user.is_authenticated(): - raise ProcessingException(description='Not authenticated', code=401) + #if not current_user.is_authenticated(): + # raise ProcessingException(description='Not authenticated', code=401) + pass def preprocessor_check_adm(*args, **kargs): - if not current_user.is_admin(): - raise ProcessingException(description='Forbidden', code=403) - + # if not current_user.is_admin(): + # raise ProcessingException(description='Forbidden', code=403) + pass def preprocessors_patch(instance_id=None, data=None, **kargs): - user_cant_change = ["admin", "clid", "id_", - "originated_calls", "received_calls, tunel"] - admin_cant_change = ["id_", "originated_calls", "received_calls"] + user_cant_change = ["level", "clid", "_id", + "originated_calls", "received_calls"] + admin_cant_change = ["_id", "originated_calls", "received_calls"] if current_user.is_admin(): for x in data.keys(): if x in admin_cant_change: @@ -197,23 +274,23 @@ def preprocessors_check_adm_or_normal_user(instance_id=None, **kargs): manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db) # Create the Flask-Restless API manager. -# Create API endpoints, which will be available at /api/ by +# Create API endpoints, which will be available at /pi/ by # default. Allowed HTTP methods can be specified as well. manager.create_api( User, preprocessors={ 'POST': [ - auth, - preprocessor_check_adm + # auth, + # preprocessor_check_adm ], 'GET_MANY': [ - auth, - preprocessor_check_adm + # auth, + # preprocessor_check_adm ], 'GET_SINGLE': [ - auth, - preprocessors_check_adm_or_normal_user + # auth, + # preprocessors_check_adm_or_normal_user ], 'PATCH_SINGLE': [ auth, @@ -223,9 +300,9 @@ def preprocessors_check_adm_or_normal_user(instance_id=None, **kargs): 'PATCH_MANY': [auth, preprocessor_check_adm], 'DELETE_SINGLE': [auth, preprocessor_check_adm], }, - postprocessors={ - 'POST':[to_openbts] - }, + postprocessors={ + 'POST': [to_openbts] + }, exclude_columns=[ 'password' ], @@ -235,35 +312,71 @@ def preprocessors_check_adm_or_normal_user(instance_id=None, **kargs): ) manager.create_api( - CDR, + Schedules, preprocessors={ 'POST': [ + # auth, + # preprocessor_check_adm, + # schedule_exists, + # put_user__idin_buffer, + transform_to_utc + ], + 'GET_MANY': [ auth, preprocessor_check_adm ], + 'GET_SINGLE': [auth, preprocessor_check_adm], + 'PATCH_SINGLE': [ + auth, + preprocessor_check_adm + ], + 'DELETE_SINGLE': [auth, preprocessor_check_adm], + }, + postprocessors={ + # 'POST': [add_dates_to_schedule, add_users_to_schedule], + 'POST': [], + }, + exclude_columns=[ + 'newUser', + 'removeUser', + 'updateSchedule' + ], + methods=['POST', 'GET', 'PATCH', 'DELETE'], + results_per_page=100 +) + +manager.create_api( + ScheduleUser, + preprocessors={ + 'POST': [ + preprocessor_check_adm, + # date_now + ], 'GET_MANY': [ auth, preprocessor_check_adm ], - 'GET_SINGLE': [ + 'GET_SINGLE': [auth, preprocessor_check_adm], + 'PATCH_SINGLE': [ auth, - preprocessors_check_adm_or_normal_user + preprocessor_check_adm ], - 'PATCH_SINGLE': [auth, preprocessors_patch], 'DELETE_SINGLE': [auth, preprocessor_check_adm], }, - methods=['POST','GET','PATCH', 'DELETE'] + postprocessors={ + 'POST': [] + }, + methods=['POST', 'GET', 'PATCH', 'DELETE'], + results_per_page=100, ) + manager.create_api( - Groups, + VoiceBalance, preprocessors={ 'POST': [ - auth, - preprocessor_check_adm, - already_has_group, - put_user_id_in_buffer, - transform_to_utc + #preprocessor_check_adm, + # date_now ], 'GET_MANY': [ auth, @@ -277,24 +390,18 @@ def preprocessors_check_adm_or_normal_user(instance_id=None, **kargs): 'DELETE_SINGLE': [auth, preprocessor_check_adm], }, postprocessors={ - 'POST': [add_dates_to_group, add_users_to_group], + 'POST': [add_user_voice_balance] }, - exclude_columns=[ - 'newUser', - 'removeUser', - 'updateGroup' - ], methods=['POST', 'GET', 'PATCH', 'DELETE'], results_per_page=100, - primary_key='name' ) manager.create_api( - Ballance, + DataBalance, preprocessors={ 'POST': [ - preprocessor_check_adm, - date_now + # preprocessor_check_adm, + # date_now ], 'GET_MANY': [ auth, @@ -308,12 +415,13 @@ def preprocessors_check_adm_or_normal_user(instance_id=None, **kargs): 'DELETE_SINGLE': [auth, preprocessor_check_adm], }, postprocessors={ - 'POST': [add_user_balance] + 'POST': [add_user_data_balance] }, methods=['POST', 'GET', 'PATCH', 'DELETE'], results_per_page=100, ) + # start the flask loop app.debug = True app.run('0.0.0.0', 5000) diff --git a/celcombiller-backend.conf b/celcombiller-backend.conf new file mode 100644 index 0000000..2ce02d6 --- /dev/null +++ b/celcombiller-backend.conf @@ -0,0 +1,21 @@ +# CELCOMBiller +# +# This service runs celcombiller backend from the point the system is +# started until it is shut down again. +# on ubuntu you have to put this file in /etc/init +# +start on runlevel [2345] + +respawn + +script + /path_to_venv/venv/bin/python /path_to_celcombiller/celcombiller/app.py +end script + +pre-start script + + touch /path_to_db/alph.db + + chmod 666 /path_to_db/alph.db + +end script diff --git a/celcombiller-frontend.conf b/celcombiller-frontend.conf new file mode 100644 index 0000000..31eb642 --- /dev/null +++ b/celcombiller-frontend.conf @@ -0,0 +1,14 @@ +# CELCOMBiller +# +# This service runs celcombiller-frontend from the point the system is +# started until it is shut down again. +# on ubuntu you have to put this file in /etc/init +# +start on runlevel [2345] + +respawn + +script + exec /path_to_gulp/gulp -gulpfile /path_to_gulpfile/gulpfile.js +end script + diff --git a/celcombiller_caller.py b/celcombiller_caller.py index f29e7f6..7f233cf 100644 --- a/celcombiller_caller.py +++ b/celcombiller_caller.py @@ -19,8 +19,7 @@ try: - agi.appexec('DIAL', 'SIP/IMSI%s@127.0.0.1:5062,40,S(%d)' %\ - (to_user.imsi, from_user.BallanceUser)) + agi.appexec('DIAL', 'SIP/IMSI%s@127.0.0.1:5062,40,S(%d)' % + (to_user.imsi, from_user.VoiceBalance)) except AGIAppError: pass - diff --git a/celcombiller_reducer.py b/celcombiller_reducer.py index 48638eb..9c2cd69 100644 --- a/celcombiller_reducer.py +++ b/celcombiller_reducer.py @@ -8,14 +8,11 @@ # pylint: disable=C0103 from datetime import datetime import asterisk.agi -#from asterisk.agi import AGIAppError from models import User - +from config import adm_user, adm_pssw import requests import json -adm_user = 'admin' -adm_pssw = 'adm123' agi = asterisk.agi.AGI() @@ -34,32 +31,23 @@ # Create a session s = requests.Session() # Login the session - s.post('http://localhost:5000/login',\ - data={'username':adm_user, 'password': adm_pssw}) - - # Create a new CDR record - payload = '{"answer":"'+ str(answer)+'", "billsec":"'+ \ - str(billsec)+'", "from_user_id": '+\ - str(from_user.id_)+', "to_user_id":'+ str(to_user.id_)+'}' - - #Send the requestto update the user balance - r = s.post('http://localhost:5000/api/cdr', json=json.loads(payload),\ - headers={'content-type': 'application/json'}) - - #TODO: Handle when the request fail - if r.ok == False: - pass - - print from_user.id_ - payload = '{"signal":"-", "type_":"decrease", "value": "'+ str(billsec) +\ - '", "userId":'+ str(from_user.id_) +'}' - - # Send the requestto update the user balance - r = s.post('http://localhost:5000/api/balance',\ - json=json.loads(payload),\ - headers={'content-type': 'application/json'}) - - #TODO: Handle when the request fail - if r.ok == False: + s.post( + 'http://localhost:5000/login', + data={'username': adm_user, 'password': adm_pssw} + ) + + payload = {'from_user_id':from_user.get_id, + 'to_user_id':to_user.get_id, + 'value':billsec*(-1), + 'origin':'call', + 'date':answer} + + # Send the request to update the user balance + r = s.post('http://localhost:5000/api/voice_balance', + json=payload, + headers={'content-type': 'application/json'}) + + # TODO: Handle when the request fail + if r.ok is False: pass s.close() diff --git a/config.py b/config.py index 86ddca0..8fd61c2 100644 --- a/config.py +++ b/config.py @@ -2,11 +2,23 @@ import flask.ext.sqlalchemy import flask.ext.restless from flask.ext.login import LoginManager +from flask.ext.cors import CORS + +# adm login and password +adm_user = 'admin' +adm_pssw = 'adm123' + +path_to_database = './alph.db' + # Create the Flask application and the Flask-SQLAlchemy object. app = flask.Flask(__name__) app.config['DEBUG'] = True -app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/alph.db' +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///'+path_to_database + + +# Ability cross domain +cors = CORS(app) db = flask.ext.sqlalchemy.SQLAlchemy(app) diff --git a/docs/dastabase.png b/docs/dastabase.png new file mode 100644 index 0000000..2991eaa Binary files /dev/null and b/docs/dastabase.png differ diff --git a/models.py b/models.py index 0806b61..e4e2593 100644 --- a/models.py +++ b/models.py @@ -4,7 +4,8 @@ from sqlalchemy.dialects.postgresql import ENUM from datetime import * -row2dict = lambda r: {c.name: str(getattr(r, c.name)) for c in r.__table__.columns} +row2dict = lambda r: {c.name: str(getattr(r, c.name)) + for c in r.__table__.columns} # Create your Flask-SQLALchemy models as usual but with the following two # (reasonable) restrictions: @@ -14,10 +15,6 @@ # all columns (the constructor in flask.ext.sqlalchemy.SQLAlchemy.Model # supplies such a method, so you don't need to declare a new one). -tunel_table = db.Table('association', db.Model.metadata, - db.Column('User_id', db.Integer, db.ForeignKey('users.id_')), - db.Column('Groups_id', db.Integer, db.ForeignKey('groups.id_')) -) class User(db.Model): """ @@ -25,16 +22,26 @@ class User(db.Model): """ __tablename__ = 'users' - id_ = db.Column(db.Integer, primary_key=True) - username = db.Column(db.Unicode, unique=True) - password = db.Column(db.Integer) - clid = db.Column(db.String(9), nullable=False, unique=True) - admin = db.Column(db.Boolean) - tunel = db.relationship('Groups', secondary=tunel_table) - imsi = db.Column(db.Integer, unique=True) - + _id = db.Column(db.Integer, primary_key=True, nullable=False) + level = db.Column(db.Integer, nullable=False) # 0=administrator, 1=users, 2=collaborator + name = db.Column(db.Unicode, nullable=False) + address = db.Column(db.Unicode) + cpf = db.Column(db.Integer, nullable=False, unique=True) + username = db.Column(db.Unicode, nullable=False, unique=True) + password = db.Column(db.Unicode, nullable=False) + clid = db.Column(db.Unicode(9), nullable=False, unique=True) + imsi = db.Column(db.Integer, nullable=False, unique=True) + voice_balance = db.Column(db.Integer, nullable=False) + data_balance = db.Column(db.Integer, nullable=False) + + # ki = db.Column(db.Integer) + # city = db.Column(db.Unicode) + # state = db.Column(db.Unicode) + # postalcode = db.Column(db.Integer) + # + def is_admin(self): - return self.admin + return (level==0 if True else False) def is_authenticated(self): return True @@ -46,146 +53,176 @@ def is_anonymous(self): return False def get_id(self): - return unicode(self.id_) + return self._id + + def VoiceBalance(self): + return self.voice_balance + + def DataBalance(self): + return self.data_balance @hybrid_property - def BallanceUser(self): + def VoiceBalanceHistoric(self): # TODO: Maybe it should use object_session - userBalanceNeg = Ballance.query.filter_by(usersId=self.id_).filter_by(signal=unicode('-')) - userBalancePos = Ballance.query.filter_by(usersId=self.id_).filter_by(signal=unicode('+')) - countNeg = 0 - countPos = 0 - for x in userBalanceNeg: - countNeg = countNeg + x.value - for x in userBalancePos: - countPos = countPos + x.value - return countPos - countNeg + balances = VoiceBalance.query.order_by( + VoiceBalance._id.desc()).filter_by(from_user_id=self._id).limit(10) + historic_list = [] + for y in balances: + historic_list.append(row2dict(y)) + return historic_list @hybrid_property - def BallanceUserHistoric(self): + def DataBalanceHistoric(self): # TODO: Maybe it should use object_session - balances = Ballance.query.order_by(Ballance.id_.desc()).filter_by(usersId=self.id_).limit(10) + balances = DataBalance.query.order_by( + DataBalance._id.desc()).filter_by(user_id=self._id).limit(10) historic_list = [] for y in balances: historic_list.append(row2dict(y)) - return historic_list - def __init__(self , username ,password, clid,admin, imsi ): - self.username = username - self.password = password - self.clid = clid - self.admin = admin - self.imsi = imsi + def __init__(self, level, name, cpf, username, password, clid, imsi, voice_balance=None, data_balance=None, address=None): + self.level = level + self.name = name + self.address = address + self.cpf = cpf + self.username = username + self.password = password + self.clid = clid + self.imsi = imsi + self.voice_balance = voice_balance + self.data_balance = data_balance def __repr__(self): return '' % (self.username) -class CDR(db.Model): - """ - Call Detail Records holds information about finished calls - """ - __tablename__ = 'cdr' - - id_ = db.Column(db.Integer, db.Sequence('cdr_id_seq'), primary_key=True) - answer = db.Column(db.DateTime) - billsec = db.Column(db.Integer) - from_user_id = db.Column(db.Integer, db.ForeignKey('users.id_')) - from_user = db.relationship('User', backref='originated_calls', - foreign_keys=from_user_id) - to_user_id = db.Column(db.Integer, db.ForeignKey('users.id_')) - to_user = db.relationship('User', backref='received_calls', - foreign_keys=to_user_id) - - def __repr__(self): - return '' % (self.from_user, self.answer, - self.billsec) -class Groups(db.Model): +class Schedules(db.Model): """ # Register Credits if """ - __tablename__ = 'groups' + __tablename__ = 'schedule' - id_ = db.Column(db.Integer, primary_key=True) + _id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Unicode) - dates_to_update = db.relationship('Dates') - tunel = db.relationship('User', secondary=tunel_table) + date = db.Column(db.DateTime) - def __init__(self, name): + def __init__(self, name, date): self.name = name + self.date = date + + def __repr__(self): + return 'schedule %r' % (self.name) + + +# this table is the association table between users and group in a +# many-to-many relationship +class ScheduleUser(db.Model): + + __tablename__ = 'schedule_user' + + user_id = db.Column(db.Integer, db.ForeignKey( + 'users._id'), primary_key=True) + group_id = db.Column(db.Integer, db.ForeignKey( + 'schedule._id'), primary_key=True) + count = db.Column(db.Integer, nullable=False) + + def __init__(self, user_id, group_id, count): + self.user_id = user_id + self.group_id = group_id + self.count = count def __repr__(self): return 'GROUPS %r' % (self.name) - @hybrid_property - def newUser(self): - return 0 - @newUser.setter - def newUser(self, userIds): - for userId in userIds: - self.tunel.append(User.query.filter_by(id_=userId).first()) - db.session.add(self) - db.session.commit() +class VoiceBalance(db.Model): + """ + Call Detail Records holds information about finished calls + """ + __tablename__ = 'voice_balance' + + _id = db.Column(db.Integer, db.Sequence('cdr_id_seq'), primary_key=True) + from_user_id = db.Column( + db.Integer, db.ForeignKey('users._id'), nullable=False) + to_user_id = db.Column(db.Integer, db.ForeignKey('users._id')) + value = db.Column(db.Integer) + date = db.Column(db.DateTime, nullable=False) + origin = db.Column(db.String, nullable=False) + + # from_user = db.relationship('User', backref='originated_calls', + # foreign_keys=from_user_id) + # to_user = db.relationship('User', backref='received_calls', + # foreign_keys=to_user_id) + + def __init__(self, from_user_id, value, origin, to_user_id=None, date=None): + self.from_user_id = from_user_id + self.to_user_id = to_user_id + self.value = value + self.origin = origin + if date is not None: + self.date = date + else: + self.date = datetime.now() + + user = db.session.query(User).filter_by(_id=from_user_id).first() + user.voice_balance = user.voice_balance + int(value) - @hybrid_property - def removeUser(self): - return 0 + def __repr__(self): + return '' % (self.from_user, self.date, + self.value) - @removeUser.setter - def removeUser(self, userIds): - for userId in userIds: - self.tunel.remove(User.query.filter_by(id_=userId).first()) - @hybrid_property - def updateGroup(self): - return 0 +# this table register the user's voice balance +class DataBalance(db.Model): - @updateGroup.setter - def updateGroup(self, check): - if check == 1: - deleteDate = Dates.query.filter_by(group_id=self.id_).first() - db.session.delete(deleteDate) - for var in self.tunel: - db.session.query(User).filter_by(id_=var.id_)\ - .update({'balance':'1250'}) + __tablename__ = 'data_balance' -class Dates(db.Model): + _id = db.Column(db.Integer, primary_key=True) + user_id = db.Column(db.Integer, db.ForeignKey('users._id')) + date = db.Column(db.DateTime()) + value = db.Column(db.Integer) + user_ip = db.Column(db.Unicode) + connection_ip = db.Column(db.Unicode) + origin = db.Column(db.Unicode, nullable=False) - __tablename__ = 'dates' + def __init__(self, user_id, value, origin, user_ip=None, connection_ip=None, date=None): - id_ = db.Column(db.Integer, primary_key=True) - group_id = db.Column(db.Integer, db.ForeignKey('groups.id_')) - date = db.Column(db.DateTime) + self.user_id = user_id + self.value = value + self.user_ip = user_ip + self.connection_ip = connection_ip + self.origin = origin - def __init__(self, date): - self.date = date + if date is not None: + self.date = date + else: + self.date = datetime.now() + + user = db.session.query(User).filter_by(_id=user_id).first() + user.data_balance = user.data_balance + int(value) def __repr__(self): - return 'DATES %r' % (self.id_) + return 'data_balance %r' % (self._id) -class Ballance(db.Model): - __tablename__ = 'balance' +class ScheduleInput(db.Model): + __tablename__ = 'schedule_input' - id_ = db.Column(db.Integer, primary_key=True) - usersId = db.Column(db.Integer, db.ForeignKey('users.id_')) - date = db.Column(db.DateTime()) - type_ = db.Column(ENUM('increase', 'decrease')) - value = db.Column(db.Integer) - signal = db.Column(db.String(1)) + _id = db.Column(db.Integer, primary_key=True) + schedule_id = db.Column(db.Integer, db.ForeignKey('schedule._id')) + voice_balance_id = db.Column( + db.Integer, db.ForeignKey('voice_balance._id')) + data_balance_id = db.Column(db.Integer, db.ForeignKey('data_balance._id')) - def __init__(self, date, type_, value, signal, usersId=None): - self.date = date - self.type_ = type_ - self.value = value - self.signal = signal - if usersId is not None: - self.usersId = usersId + def __init__(self, schedule_id, voice_balance_id, data_balance_id): + self.schedule_id = schedule_id + self.voice_balance_id = voice_balance_id + self.data_balance_id = data_balance_id def __repr__(self): - return 'balance %r' % (self.id_) + return 'schedule_input %r' % (self._id) + -# Create the database tables. +# Create the database tablesself. db.create_all() diff --git a/openbts.py b/openbts.py index d4fb787..df17642 100644 --- a/openbts.py +++ b/openbts.py @@ -1,30 +1,32 @@ -import sys import zmq +import json +def to_openbts(result=None, **kw): -def to_openbts(result = None, **kw): + for key, value in result.items(): + if key == "_id": + _id = value - id_ = "" - clid = "" - imsi = "" + elif key == "clid": + clid = value - for key,value in result.items(): - if key == "id_": - id_ = value + elif key == "imsi": + imsi = value - elif key == "clid": - clid = value + request = { + "command":"subscribers", + "action":"create", + "fields":{ + "name": str(_id), + "imsi":"IMSI" + str(imsi), + "msisdn":str(clid) , + "ki":"" + } + } - elif key == "imsi": - imsi = value - - request = '{"command":"subscribers","action":"create","fields":{"name":"' + str(id_) + '","imsi":"IMSI' + str(imsi) + '","msisdn":"' + str(clid) + '","ki":""}}' - - - context = zmq.Context() - socket = context.socket(zmq.REQ) - socket.connect("tcp://127.0.0.1:45064") - - socket.send(request) + context = zmq.Context() + socket = context.socket(zmq.REQ) + socket.connect("tcp://127.0.0.1:45064") + socket.send_string(json.dumps(request),encoding='utf-8') diff --git a/requirements.txt b/requirements.txt index 913a4d9..83ba5f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,17 @@ -pyst==0.6.50 -SQLAlchemy==0.9.9 Flask==0.10.1 +Flask-Cors==2.1.2 +Flask-Login==0.3.0 Flask-Restless==0.17.0 Flask-SQLAlchemy==2.0 -flask-login==0.3.0 +itsdangerous==0.24 +Jinja2==2.8 +MarkupSafe==0.23 +mimerender==0.6.0 +pyst2==0.4.9 +python-dateutil==2.5.3 +python-mimeparse==1.5.2 pyzmq==15.0.0 requests==2.9.0 +six==1.10.0 +SQLAlchemy==0.9.9 +Werkzeug==0.11.10 diff --git a/templates/anonymous.html b/templates/anonymous.html new file mode 100644 index 0000000..a4c1634 --- /dev/null +++ b/templates/anonymous.html @@ -0,0 +1,10 @@ + + + login + + + +

Vem Vindo

+ clique aqui para fazer login + + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 855b797..835b528 100644 --- a/templates/index.html +++ b/templates/index.html @@ -7,7 +7,7 @@ Hi {{ current_user.username }}! {% endif %} -

Vem Bindo +

Vem Vindo

\ No newline at end of file diff --git a/templates/logout.html b/templates/logout.html index a2ba607..a710d4e 100644 --- a/templates/logout.html +++ b/templates/logout.html @@ -3,12 +3,7 @@ login - {% if current_user.is_authenticated() %} - NAO EFETUOU LOGOUT {{ current_user.username }}! - {% else %} - EFETUOU LOGOUT - {% endif %} -

+

Ate mais

\ No newline at end of file