├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SMS-Back-End ├── README.md ├── apigms │ ├── README.md │ ├── api │ │ ├── __init__.py │ │ ├── apigms_api.py │ │ ├── scms_segment │ │ │ ├── __init__.py │ │ │ ├── attendance_controls_api_segment.py │ │ │ ├── disciplinary_notes_api_segment.py │ │ │ └── scms_marks_api_segment.py │ │ ├── services.py │ │ └── tdbms_segment │ │ │ ├── __init__.py │ │ │ └── tdbms_api_segment.py │ ├── apigms.yaml │ ├── appengine_config.py │ ├── docs │ │ ├── Makefile │ │ └── source │ │ │ ├── conf.py │ │ │ ├── fichero.rst │ │ │ ├── img │ │ │ └── apigateway.png │ │ │ ├── index.rst │ │ │ ├── mensajes.rst │ │ │ └── mensajesSCE.rst │ ├── requirements.txt │ └── test │ │ └── apigms_api_test.py ├── backend.png ├── dispatch.yaml ├── docs │ ├── Makefile │ └── source │ │ ├── conf.py │ │ ├── fichero.rst │ │ ├── images │ │ └── GAEApproach.jpg │ │ ├── index.rst │ │ ├── mensajes.rst │ │ └── mensajesSCE.rst ├── scms │ ├── README.md │ ├── api │ │ ├── __init__.py │ │ ├── attendance_controls_api_segment.py │ │ ├── disciplinary_notes_api_segment.py │ │ ├── marks_api_segment.py │ │ ├── scms_api_rest.py │ │ └── utils.py │ ├── appengine_config.py │ ├── das │ │ ├── README.md │ │ ├── __init__.py │ │ ├── das.py │ │ ├── local_csv_based_das.py │ │ └── provisioner │ │ │ └── das_csv_generator.py │ ├── docs │ │ ├── Makefile │ │ └── source │ │ │ ├── api.rst │ │ │ ├── api_ac_segment.rst │ │ │ ├── api_dn_segment.rst │ │ │ ├── api_m_segment.rst │ │ │ ├── attendance_controls.rst │ │ │ ├── conf.py │ │ │ ├── index.rst │ │ │ ├── models.rst │ │ │ ├── scm.models.rst │ │ │ ├── scm.rst │ │ │ ├── scm.scm.rst │ │ │ ├── scms_datastore.rst │ │ │ └── scms_general.rst │ ├── requirements.txt │ ├── scm │ │ ├── README.md │ │ ├── __init__.py │ │ ├── models │ │ │ ├── __init__.py │ │ │ ├── ac_models.py │ │ │ ├── discipline_models.py │ │ │ └── marks_models.py │ │ └── scm.py │ ├── scms.yaml │ └── test │ │ ├── AC_example_1.json │ │ ├── ADB_example_1.json │ │ ├── ADB_example_2.json │ │ ├── disciplinary_note_example_1.json │ │ ├── mark_example_1.json │ │ ├── scms_api_rest_attendance_controls_segment_test.py │ │ ├── scms_api_rest_disciplinary_notes_segment_test.py │ │ ├── scms_api_rest_marks_segment_test.py │ │ └── scms_aux_methods_test.py └── tdbms │ ├── README.md │ ├── __init__.py │ ├── appengine_config.py │ ├── dbapi │ ├── DBCreator.sql │ ├── GestorCredencialesSQL.py │ ├── README.md │ ├── __init__.py │ ├── db_params.py │ ├── entities_manager.py │ ├── productionCloudSQLInstanceINFO.py │ ├── test │ │ ├── README.md │ │ ├── sorters_tests_files │ │ │ ├── expected_sorted_list_1.json │ │ │ ├── expected_sorted_list_2.json │ │ │ ├── expected_sorted_list_3.json │ │ │ ├── expected_sorted_list_4.json │ │ │ ├── original_list_1.json │ │ │ ├── original_list_2.json │ │ │ ├── original_list_3.json │ │ │ └── original_list_4.json │ │ ├── test_entities_manager.py │ │ └── test_sorters.py │ └── utils.py │ ├── dbms_api_log.log │ ├── docs │ ├── Makefile │ └── source │ │ ├── APIDB.rst │ │ ├── DBMS_API.rst │ │ ├── anotacionesSQLCloud.md │ │ ├── conf.py │ │ ├── databaseModel.md │ │ ├── dbms_api.rst │ │ ├── gestorAlumnosSQL.rst │ │ ├── index.rst │ │ ├── tdbms_api_rest.rst │ │ └── tdbms_general.rst │ ├── img │ └── dbms_diagram.png │ ├── requirements.txt │ ├── tdbms.yaml │ ├── tdbms_api.py │ └── test │ ├── README.md │ └── dbms_api_test.py ├── SMS-Front-End ├── README.md ├── app.yaml ├── app │ ├── .bowerrc │ ├── bower.json │ ├── css │ │ └── style.css │ ├── js │ │ ├── main │ │ │ ├── global.service.js │ │ │ ├── main.module.js │ │ │ └── toast.service.js │ │ ├── studentsControl │ │ │ ├── attendanceControls │ │ │ │ ├── attendanceControl.js │ │ │ │ ├── attendanceControls.module.js │ │ │ │ ├── attendanceControls.service.js │ │ │ │ ├── attendanceControlsList.js │ │ │ │ └── newAttendanceControlDialog.js │ │ │ ├── discipline │ │ │ │ ├── DisciplinaryNoteOptionCUDDialog.js │ │ │ │ ├── disciplinaryNote.js │ │ │ │ ├── discipline.module.js │ │ │ │ ├── discipline.service.js │ │ │ │ ├── disciplineList.js │ │ │ │ └── newDisciplinaryNoteDialog.js │ │ │ └── marks │ │ │ │ ├── marks.js │ │ │ │ ├── marks.module.js │ │ │ │ └── marks.service.js │ │ └── teaching │ │ │ ├── associations │ │ │ ├── associations.module.js │ │ │ └── associations.service.js │ │ │ ├── classes │ │ │ ├── classes.module.js │ │ │ ├── classes.service.js │ │ │ ├── classesList.js │ │ │ ├── classesProfile.js │ │ │ └── newClassDialog.js │ │ │ ├── enrollments │ │ │ ├── enrollments.module.js │ │ │ └── enrollments.service.js │ │ │ ├── imparts │ │ │ ├── imparts.module.js │ │ │ └── imparts.service.js │ │ │ ├── students │ │ │ ├── newStudentDialog.js │ │ │ ├── students.module.js │ │ │ ├── students.service.js │ │ │ ├── studentsList.js │ │ │ └── studentsProfile.js │ │ │ ├── subjects │ │ │ ├── newSubjectDialog.js │ │ │ ├── subjects.module.js │ │ │ ├── subjects.service.js │ │ │ ├── subjectsList.js │ │ │ └── subjectsProfile.js │ │ │ ├── teachers │ │ │ ├── newTeacherDialog.js │ │ │ ├── teachers.module.js │ │ │ ├── teachers.service.js │ │ │ ├── teachersList.js │ │ │ └── teachersProfile.js │ │ │ ├── teaching.module.js │ │ │ └── utils │ │ │ ├── addRelation.js │ │ │ ├── chartDirective.js │ │ │ └── spinnerDirective.js │ └── views │ │ ├── home.html │ │ ├── index.html │ │ ├── studentsControl │ │ ├── attendanceControls │ │ │ ├── attendanceControl.html │ │ │ ├── attendanceControlsList.html │ │ │ └── newAttendanceControlDialog.html │ │ ├── discipline │ │ │ ├── disciplinaryNoteProfile.html │ │ │ ├── disciplineList.html │ │ │ ├── newDisciplinaryNoteDialog.html │ │ │ └── newDisciplinaryNoteOption.html │ │ └── marks │ │ │ └── marks.html │ │ └── teaching │ │ ├── classes │ │ ├── classesList.html │ │ ├── classesProfile.html │ │ └── newClassDialog.html │ │ ├── students │ │ ├── newStudentDialog.html │ │ ├── studentsList.html │ │ └── studentsProfile.html │ │ ├── subjects │ │ ├── newSubjectDialog.html │ │ ├── subjectsList.html │ │ └── subjectsProfile.html │ │ ├── teachers │ │ ├── newTeacherDialog.html │ │ ├── teachersList.html │ │ └── teachersProfile.html │ │ └── utils │ │ └── addRelationTemplate.html ├── favicon.ico ├── license.txt ├── requirements.sh └── test │ ├── geckodriver │ ├── geckodriver.log │ └── prueba.py ├── dev-requirements.txt ├── docs ├── Makefile └── source │ ├── DESPLIEGUE.md │ ├── branches.png │ ├── conf.py │ ├── gcloud.md │ ├── img │ ├── GAE_final_architecture.png │ └── sms.png │ └── index.rst ├── fabfile.py ├── provisioner ├── __init__.py └── example_data_provisioner.py ├── requirements.txt ├── requirements_bash.sh └── utils ├── count.sh ├── counter.py ├── deployInGAE-SMS-Back-End.sh ├── deployInGAE-SMS-Front-End.sh ├── mysql_install.sh ├── mysql_purge.sh └── tamProyecto.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | google_appengine/ 3 | .coverage 4 | SMS-Back-End/tdbms/lib 5 | SMS-Back-End/tdbms/dbapi/productionCloudSQLInstanceINFO.py 6 | SMS-Back-End/tdbms/docs/build 7 | SMS-Back-End/tdbms/.cache 8 | 9 | SMS-Back-End/scms/lib/ 10 | SMS-Back-End/scms/docs/build 11 | 12 | SMS-Back-End/apigms/lib/ 13 | SMS-Back-End/apigms/docs/build/ 14 | 15 | docs/build/ 16 | 17 | SMS-Front-End/app/vendor/ 18 | *.cache 19 | docs/build 20 | .idea/ 21 | 22 | _site/ 23 | 24 | lines.txt 25 | 26 | 27 | 28 | *.csv 29 | 30 | *.log 31 | .cache/ 32 | .gitignore~ 33 | Gruntfile.js 34 | SMS-Back-End/.cache/ 35 | SMS-Back-End/apigms/docs/source/_static/ 36 | SMS-Back-End/apigms/docs/source/_templates/ 37 | SMS-Back-End/apigms/test/.cache/ 38 | SMS-Back-End/apigms/test/__pycache__/ 39 | SMS-Back-End/docs/build/ 40 | SMS-Back-End/docs/source/_static/ 41 | SMS-Back-End/docs/source/_templates/ 42 | SMS-Back-End/docs/source/images/back-end.png 43 | SMS-Back-End/htmlcov/ 44 | SMS-Back-End/scms/.cache/ 45 | SMS-Back-End/scms/docs/source/NewAttendanceControlProcess.dia 46 | SMS-Back-End/scms/docs/source/NewAttendanceControlProcess.dia~ 47 | SMS-Back-End/scms/docs/source/_static/ 48 | SMS-Back-End/scms/docs/source/_templates/ 49 | SMS-Back-End/scms/docs/source/scms_diagrams.ep 50 | SMS-Back-End/scms/test/.cache/ 51 | SMS-Back-End/scms/test/__pycache__/ 52 | SMS-Back-End/tdbms/dbapi/test/__pycache__/ 53 | SMS-Back-End/tdbms/docs/source/_static/ 54 | SMS-Back-End/tdbms/docs/source/_templates/ 55 | SMS-Back-End/tdbms/test/__pycache__/ 56 | SMS-Front-End/app/images/ 57 | SMS-Front-End/docs/ 58 | SMS-Front-End/test/jasmine/ 59 | docs/build/ 60 | docs/source/_static/ 61 | docs/source/_templates/ 62 | docular_generated/ 63 | downloaded/ 64 | google-cloud-sdk/ 65 | node_modules/ 66 | package.json 67 | provisioner/aprovisionadorDatosEjemplo.py 68 | provisioner/aprovisionadorDatosEjemplo.sh 69 | provisioner/aprovisionadorDatosEjemplo.sh~ 70 | provisioner/aprovisionadorDatosEjemploOld.sh 71 | provisioner/imagenes/ 72 | venv 73 | *.tar.gz 74 | *.swp 75 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | languaje: python 2 | python: 3 | - "2.7" 4 | 5 | #dependencias requeridas: 6 | install: 7 | - sudo pip install nosegae 8 | - sudo pip install webtest 9 | - sudo pip install MySQL-python 10 | 11 | 12 | 13 | #comando para ejecutar los tests: 14 | script: nosetests -w smm/ --with-gae --gae-lib-root google_appengine/ 15 | 16 | 17 | #*Pre-installed packages Travis CI installs the following packages by default in each virtualenv: pytest nose mock 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ##Contributing Guidelines 2 | 3 | Do you want contribute in this project? **Great !!! :)** 4 | 5 | But before, we want that you know how do the things in this project to everyone follow the same way. 6 | 7 | 8 | #### Python 9 | 10 | To write python we try to follow the *[PEP-8 Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/)* as much as possible. 11 | 12 | The mainly rules for us are: 13 | 14 | * Function names: should be lowercase, with words separated by underscores as necessary to improve readability. 15 | 16 | * Constants: are usually defined on a module level and written in all capital letters with underscores separating words. 17 | Examples include MAX_OVERFLOW and TOTAL. 18 | 19 | * Class: names should normally use the CamelCase convention. 20 | 21 | * Maximum Line Length: Limit all lines to a maximum of 79 characters. 22 | 23 | * Package and Module Names: Modules should have short, all-lowercase 24 | names. Underscores can be used in the module name if it improves 25 | readability. Python packages should also have short, all-lowercase 26 | names, although the use of underscores is discouraged. 27 | 28 | * Comments: 29 | * Inline Comments. Use inline comments sparingly. An inline comment is a comment on the same 30 | line as a statement. Inline comments should be separated by at least two spaces from the statement. 31 | They should start with a # and a single space. 32 | 33 | * Block comments generally apply to some (or all) code that follows them, and are indented to the same level as that code. 34 | Each line of a block comment starts with a # and a single space (unless it is indented text inside the comment).Paragraphs inside a block comment are separated by a line containing a single # 35 | 36 | * Documentation Strings. 37 | * Conventions for writing good documentation are immortalized in PEP 257. Note that most 38 | importantly, the """ that ends a multiline docstring should be on a line by itself. 39 | * For one liner docstrings, please keep the closing """ on the same line. 40 | 41 | 42 | * Names to Avoid: Never use the characters 'l' (lowercase letter el), 43 | 'O' (uppercase letter oh), or 'I' (uppercase letter eye) as single 44 | character variable names. In some fonts, these characters are 45 | indistinguishable from the numerals one and zero. When tempted 46 | to use 'l', use 'L' instead. 47 | 48 | More details in PEP-8 guide. 49 | 50 | *Note: 51 | 52 | If you use PyCharm like us is easy to achieve this thanks her code automatic corrector. 53 | 54 | #### JavaScript 55 | 56 | 57 | Write mainly in [lowerCamelCase](http://wiki.c2.com/?LowerCamelCase) 58 | 59 | We try to follow the standard JSDoc to doc AngularJS code in JavaScript language that we develop. 60 | 61 | ####Issues, branchs, and new user stories or complete modules and microservices. 62 | 63 | 64 | **About English** 65 | 66 | 67 | * When writing English, follow Strunk and White. 68 | Python coders from non-English speaking countries: please write your 69 | comments in English, unless you are 120% sure that the code will never 70 | be read by people who don't speak your language. PEP-8.* 71 | 72 | Final note: 73 | 74 | It's only a lot of rules, but don't worry, relax and code, 75 | we only do this for fun. :) 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![License](http://img.shields.io/badge/license-GPLv3-blue.svg) 3 | ![Status](https://img.shields.io/badge/status-pre--alpha-red.svg) 4 | ![coverage](https://img.shields.io/badge/coverage-10%25-orange.svg) 5 | ![last release](https://img.shields.io/badge/last%20release-v0.1--pre--alpha-yellow.svg) 6 | 7 | ![](docs/source/img/sms.png) 8 | 9 | #### What is **SMS**? 10 | 11 | Is a system to streamline processes in studies centers of any kind and size. Is designed to improve the boring and repetitive tasks of a standard studies center, through a complete web based app (that be able to run in any devide with a simple browser) give all this time saved to the teachers and admin staff to the mainly task in a studies center, teach. 12 | While, the system will mine all these data to help you to analyce your students to help these to improve , achieve their goals fastter and better, improve the marks of your center, have a better control with special things like bullying and discipline and in generall making more productive and efficient you center, saving a lot of money and time working with paper. 13 | 14 | 15 | #### How to use SMS in your study center? 16 | 17 | In spite of this app could run in your own hardware (some server that be physically in your place of work) or in you own cloud in another IaaS like AWS, Azure, Heroku or similar, is specifically designed to run in Google App Engine, the popular PaaS of Google. The reason is simple: it offer us all that we need to run our microservices based architecture with the minimal costs, a perfect performance and be able to scal from zero to thousand of users quickly. 18 | 19 | But anyway if you want deploy it in another place you will need make some changes in the code but nothing very difficult or imposible. Of course you always can contact with us for a particular deployment or a specification of our software and support to you needs if you don't have any team that can do it. 20 | 21 | 22 | #### System Architecture 23 | 24 | The design is based on microservices, splitting the logic work in few little services running in their own domain, all independent of the rest but with a close communication based on API REST. 25 | Basic idea bhind it is to can have the perfect space to work to each section of app, with the best language, database and pattern that her domain require. 26 | 27 | ![](docs/source/img/GAE_final_architecture.png) 28 | 29 | In spite of this, this approach give the way to adjust the hardware requirements better for any service in each situation, being able to scal each one independently when the system have more users, trying to adjust the cost of the hardarware to the minimun, **thinked and developed to be deployed in the cloud**. 30 | 31 | 32 | #### Technology Stack 33 | 34 | This are the mainly technologies that we are using: 35 | 36 | - [Python](https://www.python.org/) 37 | - [Flask](http://flask.pocoo.org/) 38 | - [Javascript](https://www.javascript.com/) 39 | - [AngularJS](https://angularjs.org/) 40 | - [Angular Material](https://material.angularjs.org/latest/) 41 | - [HTML5](https://www.w3.org/TR/html5/) 42 | - [JSON](http://www.json.org/json-es.html) 43 | - [MySQL](https://www.mysql.com/) 44 | - [Google Cloud Platform](https://cloud.google.com/) 45 | 46 | 47 | #### How to know more? 48 | 49 | ###### Technical Docs 50 | 51 | You can generate the web based documentation of entire project using fabric tool to see the last verion with all new characteristics in development branch or visit the oficial last ready to production deploy version (master) **online** in Read The Docs, [here](https://readthedocs.org/). 52 | 53 | 54 | ###### Project Web Page 55 | 56 | [butterflydevs.github.io/StudentsManagementSystem](http://butterflydevs.github.io/StudentsManagementSystem/) 57 | 58 | ###### Contact 59 | 60 | If you want contact with us, please send an email to: 61 | 62 | *butterflydevsmail@gmail.com* 63 | 64 | #### How to contribute? 65 | 66 | If you want contribute with the project you only need make a **fork** of the repo, see some open issue, see the state of some of subproject or create a new issue, start to code and make a pull requests. 67 | 68 | But before please take a look at **CONTRIBUTING.md** to know how we works to follow the same way. 69 | 70 | We will happy to see you working with us ;) 71 | -------------------------------------------------------------------------------- /SMS-Back-End/README.md: -------------------------------------------------------------------------------- 1 | ##SMS Back-End 2 | 3 | It's the group of microservices that are part of SMS Back-End. We follow 4 | API Gateway Microservices Architecture Pattern (see refs [A](http://microservices.io/patterns/apigateway.html) and [B](https://www.nginx.com/blog/building-microservices-using-an-api-gateway/)) 5 | This is thinking 6 | 7 | These are intended to be deployed in the same app in Google App Engine when each microservice is actually a "service". 8 | ![](backend.png) 9 | 10 | 11 | 12 | > To run only the Back-End of app you can use fab with the option: 13 | > To run functionality test of entire Back-End: 14 | 15 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/README.md: -------------------------------------------------------------------------------- 1 | ##APIGmS 2 | 3 | ![License](http://img.shields.io/badge/license-GPLv3-blue.svg) 4 | ![PythonVersion](https://img.shields.io/badge/python-2.7-blue.svg) 5 | ![coverage](https://img.shields.io/badge/coverage-0%25-red.svg) 6 | 7 | 8 | **API Gateway micro Service**, it's the main door to system back-end. Do all communications with the rest 9 | of microservicios, to doing see at UI only one. 10 | 11 | This configuration is based in [API Gateway](http://microservices.io/patterns/apigateway.html) software design pattern. 12 | 13 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/apigms/api/__init__.py -------------------------------------------------------------------------------- /SMS-Back-End/apigms/api/apigms_api.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask.ext.cors import CORS, cross_origin 3 | from google.appengine.api import modules 4 | import requests_toolbelt.adapters.appengine 5 | 6 | # Use the App Engine Requests adapter. This makes sure that Requests uses URLFetch. 7 | requests_toolbelt.adapters.appengine.monkeypatch() 8 | 9 | app = Flask(__name__) 10 | 11 | cors = CORS(app, resources={r"/*": {"origins": "*"}}) 12 | 13 | # Activating verbose mode 14 | v = 1 15 | 16 | module = modules.get_current_module_name() 17 | instance = modules.get_current_instance_id() 18 | 19 | from tdbms_segment.tdbms_api_segment import tdbms_segment_api 20 | from scms_segment.scms_marks_api_segment import marks_api 21 | from scms_segment.disciplinary_notes_api_segment import disciplinary_notes_api 22 | from scms_segment.attendance_controls_api_segment import attendance_controls_api 23 | 24 | 25 | @app.route('/helloworld', methods=['GET']) 26 | def hello_world(): 27 | """ 28 | Test resource. 29 | 30 | :return: 31 | 32 | Example of use: 33 | curl -i -X GET localhost:8001/test 34 | """ 35 | return 'Hello world!' 36 | 37 | # Insert the rest of api sections. 38 | app.register_blueprint(tdbms_segment_api) 39 | app.register_blueprint(marks_api) 40 | app.register_blueprint(disciplinary_notes_api) 41 | app.register_blueprint(attendance_controls_api) 42 | 43 | if __name__ == '__main__': 44 | app.run(debug=True) 45 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/api/scms_segment/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/apigms/api/scms_segment/__init__.py -------------------------------------------------------------------------------- /SMS-Back-End/apigms/api/scms_segment/attendance_controls_api_segment.py: -------------------------------------------------------------------------------- 1 | ################################ 2 | # Attendance Control Resources # 3 | ################################ 4 | 5 | from flask import Blueprint 6 | from termcolor import colored 7 | from google.appengine.api import modules 8 | import requests 9 | from flask import make_response, request 10 | import requests_toolbelt.adapters.appengine 11 | requests_toolbelt.adapters.appengine.monkeypatch() 12 | 13 | 14 | import sys 15 | sys.path.insert(0, 'api') 16 | 17 | from services import CRUD 18 | 19 | attendance_controls_api = Blueprint('attendance_controls_api', __name__) 20 | 21 | 22 | @attendance_controls_api.route('/ac', methods=['GET']) 23 | @attendance_controls_api.route('/ac/', methods=['GET']) 24 | def get_ac(ac_id=None): 25 | """ 26 | It call to SCmS to get a minimal content list of all items of this kind or all info about specific one. 27 | 28 | :param ac_id: id of the item or None if the request is about all. 29 | :return: A dict with info about one or a list with dicts inside with info for each one. 30 | """ 31 | return CRUD.get(service='scms', resource='ac', id=ac_id) 32 | 33 | 34 | @attendance_controls_api.route('/ac/base/', methods=['GET']) 35 | def get_ac_base(ac_id): 36 | """ 37 | It call to SCmS to request a item (base type). 38 | 39 | :param ac_id: The id of the item in the service. 40 | :return: A dict with data. 41 | """ 42 | return CRUD.get(service='scms', resource='ac/base', id=ac_id) 43 | 44 | 45 | @attendance_controls_api.route('/ac', methods=['POST']) 46 | def post_ac(): 47 | """ 48 | It call to SCmS to post a item of this kind. 49 | 50 | :return: Dict with id saved {'acId': } in the body and specific HTTP status code in the header. 51 | """ 52 | return CRUD.post(service='scms', resource='ac', json=request.get_json()) 53 | 54 | 55 | @attendance_controls_api.route('/ac/', methods=['PUT']) 56 | def update_ac(ac_id): 57 | """ 58 | It call to SCmS to update a item ot this kind. 59 | 60 | :param ac_id: id of item to update. 61 | :return: Nothing in the body. Specific HTTP status code in the header. 62 | """ 63 | return CRUD.put(service='scms', resource='ac', id=ac_id, json=request.get_json()) 64 | 65 | 66 | @attendance_controls_api.route('/ac/', methods=['DELETE']) 67 | def delete_ac(ac_id): 68 | """ 69 | It call to SCmS to do a logic deletion of this kind of item in their data store. 70 | 71 | :param ac_id: ac id in data store. 72 | :return: Nothing in the body. Specific HTTP status code in the header. 73 | """ 74 | return CRUD.delete(service='scms', resource='ac', id=ac_id) -------------------------------------------------------------------------------- /SMS-Back-End/apigms/api/scms_segment/disciplinary_notes_api_segment.py: -------------------------------------------------------------------------------- 1 | ################################ 2 | # Disciplinary Notes Resources # 3 | ################################ 4 | 5 | from flask import Blueprint 6 | from termcolor import colored 7 | from google.appengine.api import modules 8 | import requests 9 | from flask import make_response, request 10 | import requests_toolbelt.adapters.appengine 11 | requests_toolbelt.adapters.appengine.monkeypatch() 12 | 13 | import sys 14 | sys.path.insert(0, 'api') 15 | 16 | from services import CRUD 17 | 18 | disciplinary_notes_api = Blueprint('disciplinary_notes_api', __name__) 19 | 20 | 21 | @disciplinary_notes_api.route('/disciplinarynote/schema', methods=['GET', 'PUT']) 22 | def CRU_disciplinary_note_schema(): 23 | """ 24 | It call to SCmS to get a schema with options to ve showed in UI form to do a disciplinary note. 25 | :return: A dict 26 | """ 27 | if request.method == 'GET': 28 | return CRUD.get(service='scms', resource='disciplinarynote/schema') 29 | 30 | if request.method == 'PUT': 31 | return CRUD.put(service='scms', resource='disciplinarynote/schema', id=None, json=request.get_json()) 32 | 33 | 34 | @disciplinary_notes_api.route('/disciplinarynote', methods=['GET']) 35 | @disciplinary_notes_api.route('/disciplinarynote/', methods=['GET']) 36 | def get_disciplinary_note(dn_id=None): 37 | """ 38 | It call to SCmS to get a minimal content list of all items of this kind or all info about specific one. 39 | 40 | :param ac_id: id of the item or None if the request is about all. 41 | :return: A dict with info about one or a list with dicts inside with info for each one. 42 | """ 43 | return CRUD.get(service='scms', resource='disciplinarynote', id=dn_id) 44 | 45 | 46 | @disciplinary_notes_api.route('/disciplinarynote', methods=['POST']) 47 | def post_disciplinary_note(): 48 | """ 49 | It call to SCmS to post a item of this kind. 50 | 51 | :return: Dict with id saved {'dnId': } in the body and specific HTTP status code in the header. 52 | """ 53 | return CRUD.post(service='scms', resource='disciplinarynote', json=request.get_json()) 54 | 55 | 56 | @disciplinary_notes_api.route('/disciplinarynote/', methods=['PUT']) 57 | def update_disciplinary_note(dn_id): 58 | """ 59 | It call to SCmS to update a item ot this kind. 60 | 61 | :param dn_id: id of item to update. 62 | :return: Nothing in the body. Specific HTTP status code in the header. 63 | """ 64 | return CRUD.put(service='scms', resource='disciplinarynote', id=dn_id, json=request.get_json()) 65 | 66 | 67 | @disciplinary_notes_api.route('/disciplinarynote/', methods=['DELETE']) 68 | def delete_disciplinary_note(dn_id): 69 | """ 70 | It call to SCmS to do a logic deletion of this kind of item in their data store. 71 | 72 | :param dn_id: dn id in data store. 73 | :return: Nothing in the body. Specific HTTP status code in the header. 74 | """ 75 | return CRUD.delete(service='scms', resource='disciplinarynote', id=dn_id) 76 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/api/scms_segment/scms_marks_api_segment.py: -------------------------------------------------------------------------------- 1 | ######################## 2 | # SCMS Marks Resources # 3 | ######################## 4 | 5 | 6 | from flask import Blueprint, request 7 | from termcolor import colored 8 | from google.appengine.api import modules 9 | import requests 10 | from flask import make_response, request 11 | import requests_toolbelt.adapters.appengine 12 | requests_toolbelt.adapters.appengine.monkeypatch() 13 | 14 | marks_api = Blueprint('marks_api', __name__) 15 | 16 | import sys 17 | sys.path.insert(0, 'api') 18 | 19 | from services import CRUD 20 | 21 | 22 | @marks_api.route('/mark', methods=['GET']) 23 | @marks_api.route('/mark/', methods=['GET']) 24 | def get_mark(mark_id=None): 25 | """ 26 | It call to SCmS to get a minimal content list of all items of this kind or all info about specific one. 27 | 28 | Also in this case is possible get the item using enrollmentId as param in /mark url (/mark?enrollmentId=). 29 | 30 | :param ac_id: id of the item or None if the request is about all. 31 | :return: A dict with info about one or a list with dicts inside with info for each one. 32 | """ 33 | return CRUD.get(service='scms', resource='mark', id=mark_id, args=request.args) 34 | 35 | 36 | @marks_api.route('/mark', methods=['POST']) 37 | def post_mark(): 38 | """ 39 | It call to SCmS to post a item of this kind. 40 | 41 | :return: Dict with id saved {'markId': } in the body and specific HTTP status code in the header. 42 | """ 43 | return CRUD.post(service='scms', resource='mark', json=request.get_json()) 44 | 45 | 46 | @marks_api.route('/mark/', methods=['PUT']) 47 | def update_mark(mark_id): 48 | """ 49 | It call to SCmS to update a item ot this kind. 50 | 51 | :param mark_id: id of item to update. 52 | :return: Nothing in the body. Specific HTTP status code in the header. 53 | """ 54 | return CRUD.put(service='scms', resource='mark', id=mark_id, json=request.get_json()) 55 | 56 | 57 | @marks_api.route('/mark/', methods=['DELETE']) 58 | def delete_mark(mark_id): 59 | """ 60 | It call to SCmS to do a logic deletion of this kind of item in their data store. 61 | 62 | :param mark_id: mark id in data store. 63 | :return: Nothing in the body. Specific HTTP status code in the header. 64 | """ 65 | return CRUD.delete(service='scms', resource='mark', id=mark_id) -------------------------------------------------------------------------------- /SMS-Back-End/apigms/api/services.py: -------------------------------------------------------------------------------- 1 | from google.appengine.api import modules 2 | import requests 3 | from flask import make_response, request 4 | import requests_toolbelt.adapters.appengine 5 | requests_toolbelt.adapters.appengine.monkeypatch() 6 | 7 | 8 | class CRUD(object): 9 | """ 10 | Important: 11 | The mainly goal of this class is unify the way to call all services form this. So, if in the future 12 | the way have any changes it will be for all connectors, simplify the maintenance. 13 | """ 14 | 15 | @classmethod 16 | def get(cls, service, resource, id=None, args=None): 17 | """ 18 | Do a GET request over a micro service in the backend using the params given. 19 | 20 | :param service: The name of the service (used for google services auto discovering). 21 | :param resource: The url segment of the service. 22 | :param id: The id of the request item. 23 | :param args: Args to put in the url (?paramA=<>&...) 24 | :return: Exactly the same response of the service. 25 | """ 26 | 27 | url = 'http://{}/{}'.format(modules.get_hostname(module=service), resource) 28 | 29 | if id: 30 | url += '/{}'.format(id) 31 | 32 | if args: 33 | url += '?' 34 | for arg in args: 35 | url += '{}={}&'.format(arg, args.get(arg)) 36 | url = url[:-1] 37 | 38 | response = requests.get(url, timeout=10) 39 | response.headers['Access-Control-Allow-Origin'] = "*" 40 | return make_response(response.content, response.status_code) 41 | 42 | @classmethod 43 | def post(cls, service, resource, json): 44 | """ 45 | Do a POST request over a micro service in the backend using the params given. 46 | 47 | :param service: The name of the service (used for google services auto discovering). 48 | :param resource: The url segment of the service. 49 | :param json: The payload where are the data to put in a dict format. 50 | :return: Exactly the same response of the service. 51 | """ 52 | 53 | response = requests.post(url='http://{}/{}'.format(modules.get_hostname(module=service), resource), json=json) 54 | response.headers['Access-Control-Allow-Origin'] = "*" 55 | return make_response(response.content, response.status_code) 56 | 57 | @classmethod 58 | def put(cls, service, resource, id, json): 59 | """ 60 | Do a PUT request over a micro service in the backend using the params given. 61 | 62 | :param service: The name of the service (used for google services auto discovering). 63 | :param resource: The url segment of the service. 64 | :param id: The id of the request item. **CAN BE NONE TO SINGLETON RESOURCES** 65 | :param json: The payload where are the data to put in a dict format. 66 | :return: Exactly the same response of the service. 67 | """ 68 | 69 | # For singleton resources. 70 | url = 'http://{}/{}'.format(modules.get_hostname(module=service), resource) 71 | 72 | if id: 73 | url += '/{}'.format(id) 74 | 75 | response = requests.put(url=url, json=json) 76 | response.headers['Access-Control-Allow-Origin'] = "*" 77 | return make_response(response.content, response.status_code) 78 | 79 | @classmethod 80 | def delete(cls, service, resource, id): 81 | """ 82 | Do a DELETE request over a micro service in the backend using the params given. 83 | 84 | :param service: The name of the service (used for google services auto discovering). 85 | :param resource: The url segment of the service. 86 | :param id: The id of the request item. 87 | :return: Exactly the same response of the service. 88 | """ 89 | 90 | response = requests.delete('http://{}/{}/{}'.format(modules.get_hostname(module=service), resource, id)) 91 | response.headers['Access-Control-Allow-Origin'] = "*" 92 | return make_response(response.content, response.status_code) 93 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/api/tdbms_segment/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/apigms/api/tdbms_segment/__init__.py -------------------------------------------------------------------------------- /SMS-Back-End/apigms/apigms.yaml: -------------------------------------------------------------------------------- 1 | # This file specifies your Python application's runtime configuration 2 | # including URL routing, versions, static file uploads, etc. See 3 | # https://developers.google.com/appengine/docs/python/config/appconfig 4 | # for details. 5 | 6 | # TODO: Enter your application id below. If you have signed up 7 | # using cloud.google.com/console use the "project id" for your application 8 | # id. 9 | application: 65748238734626 10 | module: default 11 | version: 1 12 | runtime: python27 13 | api_version: 1 14 | threadsafe: true 15 | 16 | automatic_scaling: 17 | min_idle_instances: 2 18 | max_pending_latency: 10s 19 | 20 | # Handlers tell App Engine how to route requests to your application. 21 | handlers: 22 | 23 | - url: /.* 24 | script: api.apigms_api.app 25 | 26 | libraries: 27 | # The pycrypto library is used for OAuth 2, and is also a requirement for 28 | # APIs that wish to authenticate users. 29 | - name: pycrypto 30 | version: latest 31 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/appengine_config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from google.appengine.ext import vendor 4 | #Para que entienda que las librerías de terceros debe buscarlas en la carpeta lib 5 | vendor.add('lib') 6 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/docs/source/fichero.rst: -------------------------------------------------------------------------------- 1 | API Gateway 2 | ============== 3 | 4 | .. automodule:: helloworld_api 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: helloworld_api.HelloWorldApi 10 | :members: 11 | 12 | .. automethod:: helloworld_api.HelloWorldApi.pruebaHolaMundo(self, request) 13 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/docs/source/img/apigateway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/apigms/docs/source/img/apigateway.png -------------------------------------------------------------------------------- /SMS-Back-End/apigms/docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. APIGateway documentation master file, created by 2 | sphinx-quickstart on Wed Jun 29 00:41:42 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to APIGateway's documentation! 7 | ====================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | fichero 15 | mensajes 16 | 17 | 18 | Indices and tables 19 | ================== 20 | 21 | * :ref:`genindex` 22 | * :ref:`modindex` 23 | * :ref:`search` 24 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/docs/source/mensajes.rst: -------------------------------------------------------------------------------- 1 | Mensajes 2 | =============== 3 | 4 | Tipo de mensajes usados por la API 5 | 6 | Contents: 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | :name: Librería de acceso a api 11 | 12 | mensajesSCE 13 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/docs/source/mensajesSCE.rst: -------------------------------------------------------------------------------- 1 | Mensajes con SCE 2 | ================ 3 | 4 | .. automodule:: mensajes.mensajesSCE 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /SMS-Back-End/apigms/requirements.txt: -------------------------------------------------------------------------------- 1 | # This requirements file lists all third-party dependencies for this project. 2 | # Este fichero de requerimientos lista todas las dependencias de terceros para este proyecto. 3 | # 4 | # Ejecute 'pip install -r requirements.txt -t lib/' para instalar estas dependencias 5 | # en el subdirectorio `lib/` . 6 | # 7 | # Note: The `lib` directory is added to `sys.path` by `appengine_config.py`. 8 | 9 | #Instalamos el cliente de python de Cloud Storage de GAE 10 | GoogleAppEngineCloudStorageClient 11 | flask==0.10 12 | flask-Testing>=0.4.1 13 | flask-cors 14 | unittest2>=0.5 15 | jsonpickle 16 | termcolor 17 | requests 18 | requests-toolbelt 19 | werkzeug 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /SMS-Back-End/backend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/backend.png -------------------------------------------------------------------------------- /SMS-Back-End/dispatch.yaml: -------------------------------------------------------------------------------- 1 | application: sms 2 | 3 | dispatch: 4 | # microsericio principal, puerta de entrada a la app 5 | - url: "*/favicon.ico" 6 | module: apigateway 7 | 8 | # microservicio de base de datos base del sistema 9 | - url: "*/sbd/*" 10 | module: sbd 11 | 12 | # microservicio de control de estudiantes 13 | - url: "*/sce/*" 14 | module: sce 15 | -------------------------------------------------------------------------------- /SMS-Back-End/docs/source/fichero.rst: -------------------------------------------------------------------------------- 1 | API Gateway 2 | ============== 3 | 4 | .. automodule:: helloworld_api 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | .. autoclass:: helloworld_api.HelloWorldApi 10 | :members: 11 | 12 | .. automethod:: helloworld_api.HelloWorldApi.pruebaHolaMundo(self, request) 13 | -------------------------------------------------------------------------------- /SMS-Back-End/docs/source/images/GAEApproach.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/docs/source/images/GAEApproach.jpg -------------------------------------------------------------------------------- /SMS-Back-End/docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. APIGateway documentation master file, created by 2 | sphinx-quickstart on Wed Jun 29 00:41:42 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | SMS Back End 7 | ============ 8 | 9 | Welcome to **SMS Back-End environment documentation**, this is the server side of *Student Management System app*. 10 | 11 | 12 | 13 | .. image:: images/back-end.png 14 | :width: 400pt 15 | 16 | 17 | 18 | 19 | Microservices availables: 20 | 21 | - `Api Gateway micro Service`_ 22 | - `Teaching Data Base micro Service`_ 23 | 24 | 25 | .. _Api Gateway micro Service: file:///home/juan/Documentos/TFG/StudentsManagementSystem/SMS-Back-End/apigms/docs/build/html/index.html 26 | .. _Teaching Data Base micro Service: file:///home/juan/Documentos/TFG/StudentsManagementSystem/SMS-Back-End/dbms/docs/build/html/index.html 27 | 28 | 29 | Indices and tables 30 | ================== 31 | 32 | * :ref:`genindex` 33 | * :ref:`modindex` 34 | * :ref:`search` 35 | -------------------------------------------------------------------------------- /SMS-Back-End/docs/source/mensajes.rst: -------------------------------------------------------------------------------- 1 | Mensajes 2 | =============== 3 | 4 | Tipo de mensajes usados por la API 5 | 6 | Contents: 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | :name: Librería de acceso a api 11 | 12 | mensajesSCE 13 | -------------------------------------------------------------------------------- /SMS-Back-End/docs/source/mensajesSCE.rst: -------------------------------------------------------------------------------- 1 | Mensajes con SCE 2 | ================ 3 | 4 | .. automodule:: mensajes.mensajesSCE 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/README.md: -------------------------------------------------------------------------------- 1 | ## SCmS 2 | 3 | ![License](http://img.shields.io/badge/license-GPLv3-blue.svg) 4 | ![PythonVersion](https://img.shields.io/badge/python-2.7-blue.svg) 5 | 6 | **Students Control micro Service** is the service that manage all task 7 | related with students controls, like attendances controls, marks and 8 | disciplinary notes, among others. 9 | 10 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/scms/api/__init__.py -------------------------------------------------------------------------------- /SMS-Back-End/scms/api/marks_api_segment.py: -------------------------------------------------------------------------------- 1 | """ 2 | Marks 3 | ===== 4 | 5 | This is the section of API that manage the resources related with this kind of objects. 6 | 7 | /mark 8 | ----- 9 | 10 | **GET** 11 | 12 | Return all marks realized with ALL info in a json **list** plus metadata. All because isn't very heavy. 13 | If there aren't any item, it will return `204 Not Found Status Code`. 14 | 15 | Example: 16 | 17 | >>> curl -i -X GET localhost:8003/mark 18 | [ 19 | { 20 | "createdAt": "2017-03-12T23:12:53.603021", 21 | "createdBy": 1, 22 | "enrollment": { 23 | "classId": 4, 24 | "enrollmentId": 42, 25 | "subjectId": 5, 26 | "teacherId": 8 27 | }, 28 | "markId": 6016527627190272, 29 | "marks": { 30 | "final": null, 31 | "firstEv": 5, 32 | "preFirstEv": 3, 33 | "preSecondEv": 8, 34 | "secondEv": 9, 35 | "thirdEv": 10 36 | }, 37 | "studentId": 5 38 | } 39 | ] 40 | 41 | **GET with params** 42 | 43 | It allows request a mark with a enrollmentId identification, as another way to make requests if we don't know 44 | markId id. 45 | 46 | Example: 47 | 48 | >>> curl -i -X GET localhost:8003/mark?enrollmentId=42 49 | 50 | Any other param aren't available and if item doesn't exists in data store will returned a 404 Not Found error, 51 | like a normal behaviour. 52 | 53 | 54 | 55 | **POST** 56 | 57 | Save in database one, return a simple http status code and **id of item stored** as a dictionary with "markId" key. 58 | 59 | Example: 60 | 61 | >>> curl -H "Content-Type: application/json" -X POST -d '...' localhost:8003/mark 62 | 63 | Post with example file: 64 | 65 | >>> curl -i -H "Content-Type: application/json" -X POST -d @SMS-Back-End/scms/test/mark_example_1.json localhost:8003/mark 66 | {"markId": 5735052650479616} 67 | 68 | An example of the send data is: 69 | 70 | .. code-block:: json 71 | 72 | { 73 | "studentId": 5, 74 | "enrollment": { 75 | "enrollmentId": 42, 76 | "classId":4, 77 | "subjectId": 5, 78 | "teacherId": 8 79 | }, 80 | "marks":{ 81 | "preFirstEv": 3, 82 | "firstEv": 5, 83 | "preSecondEv": 8, 84 | "secondEv": 9, 85 | "thirdEv": 10, 86 | "final": 9 87 | } 88 | } 89 | 90 | /mark/{id} 91 | ----------- 92 | 93 | **GET** 94 | 95 | Return a data block with all details about one mark, **metadata included**. 96 | 97 | Example: 98 | 99 | >>> curl -i -X GET localhost:8003/mark/6649846324789248 100 | { 101 | "createdAt": "2017-03-12T23:12:53.603021", 102 | "createdBy": 1, 103 | "enrollment": { 104 | "classId": 4, 105 | "enrollmentId": 42, 106 | "subjectId": 5, 107 | "teacherId": 8 108 | }, 109 | "markId": 6016527627190272, 110 | "marks": { 111 | "final": null, 112 | "firstEv": 5, 113 | "preFirstEv": 3, 114 | "preSecondEv": 8, 115 | "secondEv": 9, 116 | "thirdEv": 10 117 | }, 118 | "studentId": 5 119 | } 120 | 121 | **DELETE** 122 | 123 | Save in database one. Don't **return nothing**, you can see operation status in http response **status code**. 124 | 125 | Example: 126 | 127 | >>> curl -i -X DELETE localhost:8003/mark/324 128 | HTTP/1.1 200 OK 129 | 130 | 131 | **PUT** 132 | 133 | Update a item in data store. **Don't return nothing**, you can see operation status in http response **status code**. 134 | 135 | Example: 136 | 137 | >>> curl -i -H "Content-Type: application/json" -X PUT -d @SMS-Back-End/scms/test/mark_example_1.json localhost:8003/mark/4714705859903488 138 | HTTP/1.1 200 OK 139 | 140 | Code 141 | ---- 142 | 143 | This is the Flask code that implement segment of api use SCM (Students Controls Manager) to do all tasks. 144 | 145 | """ 146 | 147 | from flask import Blueprint, request 148 | from utils import process_response 149 | import sys 150 | sys.path.append("../") 151 | from scm.scm import MarksManager 152 | 153 | marks_api = Blueprint('marks_api', __name__) 154 | 155 | 156 | @marks_api.route('/mark', methods=['POST']) 157 | def post_mark(): 158 | """ 159 | Save a mark in the database. 160 | 161 | :return: Return HTTP status code and the mark as is saved in the data store. 162 | """ 163 | return process_response(MarksManager.post_mark(request.get_json())) 164 | 165 | 166 | @marks_api.route('/mark', methods=['GET']) 167 | @marks_api.route('/mark/', methods=['GET']) 168 | def get_mark(mark_id=None): 169 | """ 170 | Get a list of marks or a specific mark from data store. 171 | 172 | :param mark_id: The id of the mark item to searh in data store. 173 | :return: A mark object 174 | """ 175 | print request.args 176 | return process_response(MarksManager.get_mark(mark_id, request.args)) 177 | 178 | 179 | @marks_api.route('/mark/', methods=['DELETE']) 180 | def delete_mark(mark_id): 181 | """ 182 | Do a logic deletion of a mark in the data store. 183 | 184 | :param mark_id: mark id in data store 185 | :return: Nothing, normal status code 186 | """ 187 | return process_response(MarksManager.delete_mark(mark_id)) 188 | 189 | 190 | @marks_api.route('/mark/', methods=['PUT']) 191 | def update_mark(mark_id): 192 | """ 193 | Update a Mark item in the data store. 194 | 195 | :param mark_id: Mark id which will be updated. 196 | :return: Nothing 197 | """ 198 | return process_response(MarksManager.update_mark(mark_id, request.get_json())) -------------------------------------------------------------------------------- /SMS-Back-End/scms/api/scms_api_rest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from flask import Flask 4 | import json 5 | 6 | # Import the segments of api 7 | from marks_api_segment import marks_api 8 | from attendance_controls_api_segment import attendance_controls_api 9 | from disciplinary_notes_api_segment import disciplinary_notes_api 10 | 11 | # Mainly definition of flask api, linked from scms.yaml file 12 | app = Flask(__name__) 13 | 14 | ##################################################### 15 | # Definition of Data Base micro Service REST API # 16 | ##################################################### 17 | 18 | @app.route('/test',methods=['GET']) 19 | def test(): 20 | """ 21 | Test resource. 22 | 23 | Example of use: 24 | curl -i -X GET localhost:8003/test 25 | """ 26 | return json.dumps({'scms_api_rest_test_status': 'ok'}) 27 | 28 | app.register_blueprint(marks_api) 29 | app.register_blueprint(attendance_controls_api) 30 | app.register_blueprint(disciplinary_notes_api) 31 | 32 | if __name__ == '__main__': 33 | app.run(debug=True) 34 | 35 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/api/utils.py: -------------------------------------------------------------------------------- 1 | 2 | from flask import abort, make_response, Response 3 | import datetime 4 | import json 5 | 6 | 7 | class MyEncoder(json.JSONEncoder): 8 | """ 9 | Class to provide a personal way to adapt specific objects to json 10 | when the default isn't enough for us. 11 | """ 12 | 13 | def default(self, obj): 14 | if isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date): 15 | # We can select between two formats, is some places people prefer iso. 16 | #return obj.ctime() # Example: Sun Oct 16 08:23:29 2016 17 | return obj.isoformat() # Example: '2016-10-16T08:23:02 18 | 19 | return json.JSONEncoder.default(self, obj) 20 | 21 | 22 | def process_response(response): 23 | """ 24 | Process the response of AssociationManager to adapt to a api rest response, with 25 | HTTP status code instead of library status code. 26 | :param response: 27 | :return: 28 | """ 29 | 30 | if response.get('status', None) == 400: 31 | if response.get('log', None): 32 | abort(400, response['log']) 33 | 34 | elif response.get('status', None) == 404: 35 | if response.get('log', None): 36 | abort(404, response['log']) 37 | else: 38 | abort(404) 39 | 40 | elif response.get('status', None) == 500: 41 | if response.get('log', None): 42 | abort(500, response['log']) 43 | 44 | elif response.get('status', None) == 204: 45 | if not response.get('log', None): 46 | return '', 204 47 | 48 | elif response.get('status', None) == 200: 49 | 50 | # Return 200 with content in boy with json format encoder. 51 | if response.get('data', None): 52 | return make_response(Response(json.dumps(response['data'], cls=MyEncoder), mimetype='application/json')) 53 | 54 | # Return 200 Ok Status Code without body. 55 | else: 56 | return '', 200 -------------------------------------------------------------------------------- /SMS-Back-End/scms/appengine_config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from google.appengine.ext import vendor 4 | #Para que entienda que las librerías de terceros debe buscarlas en la carpeta lib 5 | vendor.add('lib') 6 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/das/README.md: -------------------------------------------------------------------------------- 1 | Data Analysis System 2 | ==================== 3 | 4 | Is the system that using the database of the micro service (Google Cloud Datastore) will make 5 | all reports about data that api will offers. -------------------------------------------------------------------------------- /SMS-Back-End/scms/das/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/scms/das/__init__.py -------------------------------------------------------------------------------- /SMS-Back-End/scms/das/das.py: -------------------------------------------------------------------------------- 1 | ############################ 2 | # Data Analysis System # 3 | ############################ 4 | 5 | #import numpy as np 6 | #import pandas as pd 7 | 8 | 9 | 10 | """ 11 | import sys 12 | # Add the ptdraft folder path to the sys.path list 13 | sys.path.append('../scm/') 14 | from termcolor import colored 15 | 16 | from scm import scm_datastore_models as models 17 | 18 | 19 | def get_general_attendance_report(): 20 | 21 | query = models.Record.query() 22 | items = [] 23 | 24 | for result in query.iter(): 25 | items.append(result.to_dict()) 26 | 27 | 28 | # Convert the list of dict in a pandas dataframe. 29 | data_frame = pd.DataFrame(items) 30 | # We extract the result of group like Series object. 31 | data_frame.groupby(['recordWeekday', 'assistance']).size() 32 | 33 | 34 | print items 35 | return {'status': 1, 'data': items, 'log': None} 36 | 37 | """ -------------------------------------------------------------------------------- /SMS-Back-End/scms/das/local_csv_based_das.py: -------------------------------------------------------------------------------- 1 | """ 2 | This program simulate the normal work of das program without DataStore, 3 | based on csv file. 4 | """ 5 | 6 | import numpy as np 7 | import pandas as pd 8 | 9 | 10 | def get_general_attendance_report(): 11 | 12 | # Read the csv, type of d is: pandas.core.frame.DataFrame 13 | d = pd.read_csv('provisioner/attendances.csv',sep=';') 14 | 15 | # To get the count of day of the week and count the assistance value: 16 | # The kind of this return is : pandas.core.series.Series 17 | recordWeekdayCount = d.groupby(['recordWeekday', 'assistance']).size() 18 | 19 | return recordWeekdayCount 20 | 21 | 22 | def get_students_attendance_report(): 23 | 24 | data_frame = pd.read_csv('provisioner/attendances.csv', sep=';') 25 | serie = data_frame.groupby(['studentId','assistance']).size() 26 | 27 | return serie 28 | 29 | if __name__ == "__main__": 30 | 31 | print (get_general_attendance_report()) 32 | print (get_students_attendance_report()) -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/api.rst: -------------------------------------------------------------------------------- 1 | .. MicroServicio Base de Datos documentation master file, created by 2 | sphinx-quickstart on Thu Jun 30 18:09:45 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | API 7 | ======================================================= 8 | 9 | The door to SCmS resources, splited in three sections, each one to each kind of data that this micro service 10 | manage. 11 | 12 | 13 | .. toctree:: 14 | :maxdepth: 2 15 | 16 | api_ac_segment 17 | api_m_segment 18 | api_dn_segment 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/api_ac_segment.rst: -------------------------------------------------------------------------------- 1 | .. MicroServicio Base de Datos documentation master file, created by 2 | sphinx-quickstart on Thu Jun 30 18:09:45 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | .. automodule:: api.attendance_controls_api_segment 7 | :members: 8 | :undoc-members: 9 | :show-inheritance: 10 | 11 | 12 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/api_dn_segment.rst: -------------------------------------------------------------------------------- 1 | .. MicroServicio Base de Datos documentation master file, created by 2 | sphinx-quickstart on Thu Jun 30 18:09:45 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | .. automodule:: api.disciplinary_notes_api_segment 7 | :members: 8 | :undoc-members: 9 | :show-inheritance: 10 | 11 | 12 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/api_m_segment.rst: -------------------------------------------------------------------------------- 1 | .. MicroServicio Base de Datos documentation master file, created by 2 | sphinx-quickstart on Thu Jun 30 18:09:45 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | .. automodule:: api.marks_api_segment 7 | :members: 8 | :undoc-members: 9 | :show-inheritance: 10 | 11 | 12 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/attendance_controls.rst: -------------------------------------------------------------------------------- 1 | **AttendanceControls** 2 | ========================== 3 | 4 | Domain 5 | ------------ 6 | 7 | This microservice make possible the control of attendance and discipline of the students in the system. 8 | Using a database object oriented make very easy the data process and analysis, the core of the domain 9 | of this service... 10 | 11 | 12 | API 13 | ------------ 14 | 15 | GET /ac/base/{id} 16 | 17 | Return a datablock with the datablock that represent the Attendance Control to be showed in the user interface. 18 | 19 | See :ref:`external-libraries` 20 | 21 | GET /ac or /ac/{id} 22 | 23 | :py:meth:`scms_api_rest.get_ac` 24 | :py:meth:`scm.scm.AttendanceControlsManager.get_ac` 25 | 26 | Return a dataclock with a the list with minimal info of all attendance controls realized or all details about one. 27 | 28 | POST /ac 29 | 30 | Save in database one, return a simple http status code. 31 | 32 | DEL /ac/{id} 33 | 34 | Del the item with id sended, return a scimple http status code. 35 | 36 | - 200: Success 37 | - 404: Not found 38 | 39 | 40 | 41 | Data base 42 | ---------- 43 | 44 | Is thinking to run with a Google Cloud Storage, connected with NDB library, but with this form is easy 45 | to pass to another kind of database like MongoDB or something like this. The coplexity of this mService 46 | is very low. 47 | 48 | Data structures 49 | --------------- 50 | 51 | This microService work with different kinds of data structures. We are take a look over there: 52 | 53 | **ADB** (*Association Data Block*) 54 | 55 | Is the base of microservice, is the data structure that define the compound of the groups of students, 56 | in some class, in some subject and with some teacher. 57 | 58 | The api offers a simple CRUD methods to interact with this resource, to get, put, post and delete it. 59 | 60 | The model of this data structure is: 61 | 62 | .. code-block:: json 63 | 64 | association = { 65 | 'association': { 66 | 'associationId': 13, 67 | 'class': {'classId': 283, 'classWord': 'A', 'classCourse': 2, 'classLevel': 'Elementary'}, 68 | 'subject': {'subjectId': 24, 'subjectName': 'Pruebas'} 69 | }, 70 | 'teacher': {'teacherId': 213, 71 | 'teacherName': 'asdk', 72 | 'teacherSurname': 'sdlkfjs', 73 | 'teacherImgProfile': 'www.google.es'}, 74 | 75 | 'students': [{'studentId': 213, 76 | 'studentName': 'asdk', 77 | 'studentSurname': 'sdlkfjs', 78 | 'studentImgProfile': 'www.google.es'}, 79 | 80 | {'studentId': 213, 81 | 'studentName': 'asdk', 82 | 'studentSurname': 'sdlkfjs', 83 | 'studentImgProfile': 'www.google.es'} 84 | ] 85 | } 86 | 87 | 88 | 89 | 90 | *The datatype are very important and must be right. 91 | 92 | Metadata schema 93 | --------------- 94 | - This API Rest work only with JSON data format, to send data and to receive. 95 | - In spite of exists another tables in data model like *Impart*, *Association*, and *Enrollment* that represent different kinds of relations between entities this aren't accessible directly like nested resources from the API, but yes like unique. :: 96 | 97 | ../teacher/n/impart 98 | ... 99 | 400 Bad Request 100 | ... 101 | 102 | 103 | Code 104 | --------------- 105 | 106 | .. toctree:: 107 | :maxdepth: 1 108 | 109 | api 110 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. MicroServicio Base de Datos documentation master file, created by 2 | sphinx-quickstart on Thu Jun 30 18:09:45 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Students Control microService documentation! 7 | ======================================================= 8 | 9 | This is amaizing service to do this stuffs. 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | api 15 | scm 16 | 17 | 18 | .. warning:: This mService depends to TDBmS to populate extra info to many items that this return in some resources. Because of that there must be a consistency between of them. 19 | 20 | 21 | Indices and tables 22 | ================== 23 | 24 | * :ref:`genindex` 25 | * :ref:`modindex` 26 | * :ref:`search` 27 | 28 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/models.rst: -------------------------------------------------------------------------------- 1 | Models 2 | ======================================================= 3 | 4 | Models 5 | 6 | 7 | 8 | .. automodule:: scm.models.ac_models 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/scm.models.rst: -------------------------------------------------------------------------------- 1 | .. MicroServicio Base de Datos documentation master file, created by 2 | sphinx-quickstart on Thu Jun 30 18:09:45 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Models 7 | ====== 8 | 9 | .. automodule:: scm.models.ac_models 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | 14 | .. automodule:: scm.models.discipline_models 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | .. automodule:: scm.models.marks_models 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | 24 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/scm.rst: -------------------------------------------------------------------------------- 1 | .. MicroServicio Base de Datos documentation master file, created by 2 | sphinx-quickstart on Thu Jun 30 18:09:45 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | SCM 7 | ======================================================= 8 | 9 | Students Control Manager 10 | 11 | 12 | .. toctree:: 13 | :maxdepth: 2 14 | 15 | scm.scm 16 | scm.models 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/scm.scm.rst: -------------------------------------------------------------------------------- 1 | .. MicroServicio Base de Datos documentation master file, created by 2 | sphinx-quickstart on Thu Jun 30 18:09:45 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | .. automodule:: scm.scm 7 | :members: 8 | :undoc-members: 9 | :show-inheritance: 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/scms_datastore.rst: -------------------------------------------------------------------------------- 1 | **DataStore General Info** 2 | ========================== 3 | 4 | 5 | 6 | 7 | Data is written to Cloud Datastore in objects known as entities. Each entity has a key that uniquely identifies it -------------------------------------------------------------------------------- /SMS-Back-End/scms/docs/source/scms_general.rst: -------------------------------------------------------------------------------- 1 | **General Info** 2 | ======================== 3 | 4 | Imagen de la estructura 5 | 6 | Imagen del modelo de la base de datos. 7 | 8 | Domain 9 | ------------ 10 | 11 | This microservice make possible the control of attendance and discipline of the students in the system. 12 | Using a database object oriented make very easy the data process and analysis, the core of the domain 13 | of this service 14 | 15 | Data base 16 | ---------- 17 | 18 | Is thinking to run with a Google Cloud Storage, connected with NDB library, but with this form is easy 19 | to pass to another kind of database like MongoDB or something like this. The coplexity of this mService 20 | is very low. 21 | 22 | Data structures 23 | --------------- 24 | 25 | This microService work with different kinds of data structures. We are take a look over there: 26 | 27 | **ADB** (*Association Data Block*) 28 | 29 | Is the base of microservice, is the data structure that define the compound of the groups of students, 30 | in some class, in some subject and with some teacher. 31 | 32 | The api offers a simple CRUD methods to interact with this resource, to get, put, post and delete it. 33 | 34 | The model of this data structure is: 35 | 36 | .. code-block:: json 37 | 38 | association = { 39 | 'association': { 40 | 'associationId': 13, 41 | 'class': {'classId': 283, 'classWord': 'A', 'classCourse': 2, 'classLevel': 'Elementary'}, 42 | 'subject': {'subjectId': 24, 'subjectName': 'Pruebas'} 43 | }, 44 | 'teacher': {'teacherId': 213, 45 | 'teacherName': 'asdk', 46 | 'teacherSurname': 'sdlkfjs', 47 | 'teacherImgProfile': 'www.google.es'}, 48 | 49 | 'students': [{'studentId': 213, 50 | 'studentName': 'asdk', 51 | 'studentSurname': 'sdlkfjs', 52 | 'studentImgProfile': 'www.google.es'}, 53 | 54 | {'studentId': 213, 55 | 'studentName': 'asdk', 56 | 'studentSurname': 'sdlkfjs', 57 | 'studentImgProfile': 'www.google.es'} 58 | ] 59 | } 60 | 61 | 62 | 63 | 64 | *The datatype are very important and must be right. 65 | 66 | Metadata schema 67 | --------------- 68 | - This API Rest work only with JSON data format, to send data and to receive. 69 | - In spite of exists another tables in data model like *Impart*, *Association*, and *Enrollment* that represent different kinds of relations between entities this aren't accessible directly like nested resources from the API, but yes like unique. :: 70 | 71 | ../teacher/n/impart 72 | ... 73 | 400 Bad Request 74 | ... 75 | 76 | 77 | Code: 78 | 79 | link to files -------------------------------------------------------------------------------- /SMS-Back-End/scms/requirements.txt: -------------------------------------------------------------------------------- 1 | # This file install all requirements that python needs in this micro service to run in isolate mode. 2 | # 3 | # Run 'pip install -r requirements.txt -t lib/' to install dependencies in lib/ folder. 4 | # 5 | # Note: The `lib` directory is added to `sys.path` by `appengine_config.py`. 6 | Flask==0.10 7 | Flask-Testing>=0.4.1 8 | flask-cors 9 | unittest2>=0.5 10 | jsonpickle 11 | termcolor 12 | pytz 13 | requests 14 | requests-toolbelt 15 | 16 | # For data science 17 | #scipy 18 | #numpy 19 | pandas -------------------------------------------------------------------------------- /SMS-Back-End/scms/scm/README.md: -------------------------------------------------------------------------------- 1 | Students Control Manager 2 | ------------------------ 3 | 4 | The library between the api rest and database. -------------------------------------------------------------------------------- /SMS-Back-End/scms/scm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/scms/scm/__init__.py -------------------------------------------------------------------------------- /SMS-Back-End/scms/scm/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/scms/scm/models/__init__.py -------------------------------------------------------------------------------- /SMS-Back-End/scms/scm/models/ac_models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 4 | Attendance Control Model 5 | ======================== 6 | 7 | This model represent the kind of object **Attendance Control**, that is the object used to save the attendance 8 | control of a group of students in a class and in a specific subject. 9 | 10 | .. note:: Attention: We don't respect PEP-8 style guide because we use camelCase in the JSON files that the apis manage and the conversion to json is directly using the same name used here. 11 | 12 | """ 13 | 14 | from google.appengine.ext import ndb 15 | 16 | 17 | class ACAssociation(ndb.Model): 18 | 19 | associationId = ndb.IntegerProperty() 20 | classId = ndb.IntegerProperty() 21 | subjectId = ndb.IntegerProperty() 22 | 23 | 24 | class CKS(ndb.Model): 25 | 26 | assistance = ndb.BooleanProperty() 27 | delay = ndb.IntegerProperty() 28 | justifiedDelay = ndb.BooleanProperty() 29 | uniform = ndb.BooleanProperty() 30 | 31 | 32 | class ACStudent(ndb.Model): 33 | 34 | studentId = ndb.IntegerProperty() 35 | control = ndb.StructuredProperty(CKS) 36 | 37 | 38 | class AC(ndb.Model): 39 | """ 40 | Attendance Control Data Block DataStore Model. 41 | Is the ... 42 | """ 43 | 44 | association = ndb.StructuredProperty(ACAssociation) 45 | teacherId = ndb.IntegerProperty() 46 | students = ndb.StructuredProperty(ACStudent, repeated=True) 47 | 48 | # Metadata # 49 | 50 | createdBy = ndb.IntegerProperty() 51 | createdAt = ndb.DateTimeProperty() 52 | 53 | modifiedBy = ndb.IntegerProperty(default=None) 54 | modifiedAt = ndb.DateTimeProperty(default=None) 55 | 56 | deletedBy = ndb.IntegerProperty(default=None) 57 | deletedAt = ndb.DateTimeProperty(default=None) 58 | 59 | deleted = ndb.BooleanProperty(default=False) 60 | 61 | @classmethod 62 | def get_ac(cls, ac_id): 63 | key = ndb.Key('AC', long(ac_id)) 64 | query = AC.query(AC.key == key) 65 | return query 66 | 67 | 68 | ################################################# 69 | # Record Data Block DataStore Model # 70 | ################################################# 71 | class Record(ndb.Model): 72 | 73 | # Student Identification and properties 74 | studentId = ndb.IntegerProperty() 75 | # age = ndb.IntegerProperty() 76 | 77 | # CKS Base 78 | assistance = ndb.BooleanProperty() 79 | delay = ndb.IntegerProperty() 80 | justifiedDelay = ndb.BooleanProperty() 81 | uniform = ndb.BooleanProperty() 82 | 83 | # Related Items Metadata 84 | associationId = ndb.IntegerProperty() 85 | subjectId = ndb.IntegerProperty() 86 | classId = ndb.IntegerProperty() 87 | teacherId = ndb.IntegerProperty() 88 | 89 | # Time Metadata 90 | recordDate = ndb.DateTimeProperty() 91 | recordWeekday = ndb.IntegerProperty() -------------------------------------------------------------------------------- /SMS-Back-End/scms/scm/models/discipline_models.py: -------------------------------------------------------------------------------- 1 | """ 2 | Disciplinary Note Model 3 | ======================= 4 | 5 | .. note:: Attention: We don't respect PEP-8 style. 6 | """ 7 | from google.appengine.ext import ndb 8 | 9 | ################################################ 10 | # Disciplinary Note Data Block DataStore Model # 11 | ################################################ 12 | 13 | # Attention: We don't respect PEP-8 style guide because we use camelCase in the JSON files that 14 | # the api manage and the conversion to json is directly using the same name used here. 15 | 16 | 17 | class OptionItem(ndb.Model): 18 | id = ndb.IntegerProperty() 19 | meaning = ndb.StringProperty() 20 | 21 | 22 | # This is a singleton MODEL 23 | class DNOptions(ndb.Model): 24 | kinds = ndb.StructuredProperty(OptionItem, repeated=True) 25 | gravities = ndb.StructuredProperty(OptionItem, repeated=True) 26 | modifiedBy = ndb.IntegerProperty() 27 | modifiedAt = ndb.DateTimeProperty() 28 | 29 | 30 | class DisciplinaryNote(ndb.Model): 31 | """ 32 | Model of a disciplinary note. We save only the id of students and teacher. One disciplinary note 33 | is done over a student and maybe done in a class while a subject is impart, but maybe don't. Because 34 | of this this attributes can be empty. We don't save enrollmentId, we prefer save directly class and 35 | subject references. 36 | """ 37 | 38 | # Related academic info. 39 | studentId = ndb.IntegerProperty() 40 | teacherId = ndb.IntegerProperty() 41 | classId = ndb.IntegerProperty() 42 | subjectId = ndb.IntegerProperty() 43 | 44 | # Disciplinary Note 45 | kind = ndb.IntegerProperty() 46 | gravity = ndb.IntegerProperty() 47 | description = ndb.StringProperty() 48 | dateTime = ndb.DateTimeProperty() 49 | 50 | # Item Metadata 51 | createdBy = ndb.IntegerProperty() 52 | createdAt = ndb.DateTimeProperty() 53 | modifiedBy = ndb.IntegerProperty(default=None) 54 | modifiedAt = ndb.DateTimeProperty(default=None) 55 | deletedBy = ndb.IntegerProperty(default=None) 56 | deletedAt = ndb.DateTimeProperty(default=None) 57 | deleted = ndb.BooleanProperty(default=False) -------------------------------------------------------------------------------- /SMS-Back-End/scms/scm/models/marks_models.py: -------------------------------------------------------------------------------- 1 | """ 2 | Mark Model 3 | ========== 4 | 5 | .. note:: Attention: We don't respect PEP-8 style. 6 | """ 7 | from google.appengine.ext import ndb 8 | 9 | #################################### 10 | # Mark Data Block DataStore Model # 11 | #################################### 12 | 13 | # Attention: We don't respect PEP-8 style guide because we use camelCase in the JSON files that 14 | # the apis manage and the conversion to json is directly using the same name used here. 15 | 16 | 17 | class Enrollment(ndb.Model): 18 | enrollmentId = ndb.IntegerProperty() 19 | classId = ndb.IntegerProperty() 20 | subjectId = ndb.IntegerProperty() 21 | teacherId = ndb.IntegerProperty() 22 | 23 | 24 | class Marks(ndb.Model): 25 | 26 | # Mark base 27 | preFirstEv = ndb.FloatProperty() 28 | firstEv = ndb.FloatProperty() 29 | 30 | preSecondEv = ndb.FloatProperty() 31 | secondEv = ndb.FloatProperty() 32 | 33 | thirdEv = ndb.FloatProperty() 34 | 35 | final = ndb.FloatProperty() 36 | 37 | 38 | class Mark(ndb.Model): 39 | 40 | # Student Identification and properties 41 | studentId = ndb.IntegerProperty() 42 | enrollment = ndb.StructuredProperty(Enrollment) 43 | 44 | marks = ndb.StructuredProperty(Marks) 45 | 46 | # Mark Item Metadata 47 | createdBy = ndb.IntegerProperty() 48 | createdAt = ndb.DateTimeProperty() 49 | 50 | modifiedBy = ndb.IntegerProperty(default=None) 51 | modifiedAt = ndb.DateTimeProperty(default=None) 52 | 53 | deletedBy = ndb.IntegerProperty(default=None) 54 | deletedAt = ndb.DateTimeProperty(default=None) 55 | 56 | deleted = ndb.BooleanProperty(default=False) 57 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/scms.yaml: -------------------------------------------------------------------------------- 1 | application: 65748238734626 2 | module: scms 3 | version: uno 4 | runtime: python27 5 | env: flex 6 | api_version: 1 7 | threadsafe: true 8 | 9 | automatic_scaling: 10 | min_idle_instances: 2 11 | max_pending_latency: 10s 12 | 13 | handlers: 14 | - url: /.* 15 | script: api.scms_api_rest.app 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/test/AC_example_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "students": [ 3 | { 4 | "control": { 5 | "delay": 0, 6 | "assistance": true, 7 | "uniform": true, 8 | "justifiedDelay": true 9 | }, 10 | "studentId": 2 11 | }, 12 | { 13 | "control": { 14 | "delay": 0, 15 | "assistance": true, 16 | "uniform": true, 17 | "justifiedDelay": true 18 | }, 19 | "studentId": 1 20 | } 21 | ], 22 | "teacherId": 1, 23 | "association": { 24 | "associationId": 1, 25 | "classId": 1, 26 | "subjectId": 1 27 | } 28 | } -------------------------------------------------------------------------------- /SMS-Back-End/scms/test/ADB_example_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "association": { 3 | 4 | "associationId": 13, 5 | 6 | "class": { 7 | "classId": 283, 8 | "word": "A", 9 | "course": 2, 10 | "level": "Elementary" 11 | }, 12 | 13 | "subject": { 14 | "subjectId": 24, 15 | "name": "Pruebas" 16 | } 17 | 18 | }, 19 | "teacher": { 20 | "teacherId": 23, 21 | "name": "teacherA", 22 | "surname": "teacherB", 23 | "imgProfile": "picTeacher" 24 | }, 25 | "students": [ 26 | { 27 | "studentId": 113, 28 | "name": "nameA", 29 | "surname": "surnameA", 30 | "imgProfile": "pic2" 31 | }, 32 | { 33 | "studentId": 213, 34 | "name": "nameB", 35 | "surname": "surnameB", 36 | "imgProfile": "pic1" 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /SMS-Back-End/scms/test/ADB_example_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "association": { 3 | "associationId": 13, 4 | "class": { 5 | "classId": 283, 6 | "classWord": "A", 7 | "classCourse": 2, 8 | "classLevel": "Elementary" 9 | }, 10 | "subject": { 11 | "subjectId": 24, 12 | "subjectName": "Pruebas" 13 | } 14 | }, 15 | "teacher": { 16 | "teacherId": 213, 17 | "teacherName": "teacherName", 18 | "teacherSurname": "teacherSurname", 19 | "teacherImgProfile": "www.google.es" 20 | }, 21 | "students": [ 22 | { 23 | "studentId": 581, 24 | "studentName": "SuperName", 25 | "studentSurname": "Surname", 26 | "studentImgProfile": "www.google.es" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /SMS-Back-End/scms/test/disciplinary_note_example_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "studentId": 5, 3 | "teacherId": 42, 4 | "classId": 3, 5 | "subjectId": 21, 6 | "dateTime": "2000-12-03 10:30", 7 | "kind": 1, 8 | "gravity": 5, 9 | "description": "A little problem with new boy. María" 10 | } 11 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/test/mark_example_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "studentId": 5, 3 | "enrollment": { 4 | "enrollmentId": 42, 5 | "classId":4, 6 | "subjectId": 5, 7 | "teacherId": 8 8 | }, 9 | "marks":{ 10 | "preFirstEv": 3, 11 | "firstEv": 5, 12 | "preSecondEv": 8, 13 | "secondEv": 9, 14 | "thirdEv": 10, 15 | "final": 104 16 | } 17 | } -------------------------------------------------------------------------------- /SMS-Back-End/scms/test/scms_api_rest_attendance_controls_segment_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | ########################################################## 3 | ### SCmS attendance controls api segment test suite ### 4 | ########################################################## 5 | """ 6 | import requests 7 | import json 8 | from time import sleep 9 | 10 | 11 | def pytest_generate_tests(metafunc): 12 | """ 13 | Config function to make the test to several scenarios. 14 | """ 15 | idlist = [] 16 | argvalues = [] 17 | for scenario in metafunc.cls.scenarios: 18 | idlist.append(scenario[0]) 19 | items = scenario[1].items() 20 | argnames = [x[0] for x in items] 21 | argvalues.append(([x[1] for x in items])) 22 | metafunc.parametrize(argnames, argvalues, ids=idlist, scope="class") 23 | 24 | scenario1 = ('calling mService directly', {'port': '8003'}) 25 | scenario2 = ('calling mService through APIG', {'port': '8001'}) 26 | 27 | 28 | class TestClass(object): 29 | 30 | scenarios = [scenario1, scenario2] 31 | 32 | def test_empty_ac_items_in_data_store(self, port): 33 | 34 | url_base = 'http://localhost:{}/ac'.format(port) 35 | 36 | result = requests.get(url_base) 37 | assert result.status_code == 204 38 | 39 | # Item doesn't exist. 40 | result = requests.get(url_base+'/2239') 41 | assert result.status_code == 404 42 | 43 | def test_post_and_delete(self, port): 44 | 45 | url_base = 'http://localhost:{}/ac'.format(port) 46 | 47 | # Open JSON from file 48 | with open('test/AC_example_1.json') as data_file: 49 | data = json.load(data_file) 50 | response = requests.post(url=url_base, json=data) 51 | assert response.status_code == 200 52 | 53 | # Because the Asynchrony of the server. 54 | sleep(0.5) # Time in seconds. 55 | 56 | result = requests.get(url_base) 57 | assert result.status_code == 200 58 | assert len(result.json()) == 1 59 | 60 | response = requests.delete(url='{}/{}'.format(url_base, response.json()['acId'])) 61 | assert response.status_code == 200 62 | 63 | sleep(0.5) 64 | 65 | result = requests.get(url_base) 66 | assert result.status_code == 204 67 | 68 | def test_update(self, port): 69 | 70 | url_base = 'http://localhost:{}/ac'.format(port) 71 | 72 | with open('test/AC_example_1.json') as data_file: 73 | data = json.load(data_file) 74 | response = requests.post(url=url_base, json=data) 75 | assert response.status_code == 200 76 | ac_id = response.json()['acId'] 77 | 78 | sleep(0.5) 79 | # A part of data is modified. 80 | data['students'][0]['control']['delay'] = 15 81 | 82 | response = requests.put(url='{}/{}'.format(url_base,ac_id), json=data) 83 | assert response.status_code == 200 84 | 85 | sleep(0.5) 86 | 87 | # Check the update 88 | response = requests.get(url='{}/{}'.format(url_base, ac_id)) 89 | assert response.status_code == 200 90 | ac = response.json() 91 | assert ac['students'][0]['control']['delay'] == 15 92 | 93 | response = requests.delete(url='{}/{}'.format(url_base, ac_id)) 94 | assert response.status_code == 200 95 | 96 | sleep(0.5) 97 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/test/scms_api_rest_marks_segment_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | ########################################################## 3 | ### SCmS marks api segment TEST SUITE ### 4 | ########################################################## 5 | """ 6 | import requests 7 | from time import sleep 8 | import json 9 | 10 | def pytest_generate_tests(metafunc): 11 | """ 12 | Config function to make the test to several scenarios. 13 | """ 14 | idlist = [] 15 | argvalues = [] 16 | for scenario in metafunc.cls.scenarios: 17 | idlist.append(scenario[0]) 18 | items = scenario[1].items() 19 | argnames = [x[0] for x in items] 20 | argvalues.append(([x[1] for x in items])) 21 | metafunc.parametrize(argnames, argvalues, ids=idlist, scope="class") 22 | 23 | scenario1 = ('calling mService directly', {'port': '8003'}) 24 | scenario2 = ('calling mService through APIG', {'port': '8001'}) 25 | 26 | 27 | class TestClass(object): 28 | 29 | scenarios = [scenario1, scenario2] 30 | 31 | @classmethod 32 | def check_mark_with_original(cls, mark, mark2): 33 | 34 | # In the get a Mark returned must have all values from original mark plus 35 | # the metadata 'createdBy', 'createdAt' and 'markId' 36 | assert mark.get('createdBy', None) 37 | assert mark.get('createdAt', None) 38 | assert mark.get('markId', None) 39 | 40 | # And the rest of values of the mark saved: 41 | for k, v in mark2.items(): 42 | assert mark[k] == v 43 | 44 | def test_empty_mark_items_in_data_store(self, port): 45 | 46 | url = 'http://localhost:{}/mark'.format(port) 47 | 48 | result = requests.get(url) 49 | assert result.status_code == 204 50 | 51 | # Item doesn't exist. 52 | result = requests.get(url+'/2239') 53 | assert result.status_code == 404 54 | 55 | # Item searched with enrollmentId doesn't exists. 56 | result = requests.get(url + '?enrollmentId=423') 57 | assert result.status_code == 404 58 | 59 | def test_post_and_delete(self, port): 60 | 61 | url = 'http://localhost:{}/mark'.format(port) 62 | 63 | # Open JSON from file 64 | with open('test/mark_example_1.json') as data_file: 65 | data = json.load(data_file) 66 | response = requests.post(url=url, json=data) 67 | assert response.status_code == 200 68 | 69 | # Because the Asynchronously of the server. 70 | sleep(0.5) # Time in seconds. 71 | 72 | result = requests.get(url) 73 | assert result.status_code == 200 74 | assert len(result.json()) == 1 75 | 76 | # Item searched with enrollmentId exists. 77 | result = requests.get(url='{}{}{}'.format(url,'?enrollmentId=',data['enrollment']['enrollmentId'])) 78 | assert result.status_code == 200 79 | 80 | response = requests.delete(url='{}/{}'.format(url, response.json()['markId'])) 81 | assert response.status_code == 200 82 | 83 | sleep(0.5) 84 | 85 | result = requests.get(url) 86 | assert result.status_code == 204 87 | 88 | def test_update(self, port): 89 | 90 | url = 'http://localhost:{}/mark'.format(port) 91 | 92 | with open('test/mark_example_1.json') as data_file: 93 | data = json.load(data_file) 94 | response = requests.post(url=url, json=data) 95 | assert response.status_code == 200 96 | ac_id = response.json()['markId'] 97 | 98 | sleep(0.5) 99 | # A part of data is modified. 100 | data['marks']['preFirstEv'] = 7.6 101 | 102 | response = requests.put(url='{}/{}'.format(url,ac_id), json=data) 103 | assert response.status_code == 200 104 | 105 | sleep(0.5) 106 | 107 | # Check the update 108 | response = requests.get(url='{}/{}'.format(url, ac_id)) 109 | assert response.status_code == 200 110 | ac = response.json() 111 | assert data['marks']['preFirstEv'] == 7.6 112 | 113 | response = requests.delete(url='{}/{}'.format(url, ac_id)) 114 | assert response.status_code == 200 115 | 116 | sleep(0.5) 117 | -------------------------------------------------------------------------------- /SMS-Back-End/scms/test/scms_aux_methods_test.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import os 3 | from termcolor import colored 4 | import datetime 5 | from time import sleep 6 | 7 | 8 | class TestClass: 9 | pass 10 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/README.md: -------------------------------------------------------------------------------- 1 | ## TDBmS 2 | 3 | ![License](http://img.shields.io/badge/license-GPLv3-blue.svg) 4 | ![PythonVersion](https://img.shields.io/badge/python-2.7-blue.svg) 5 | ![coverage](https://img.shields.io/badge/coverage-30%25-orange.svg) 6 | 7 | **Teaching Data Base micro Service** provide the relational data base that the app needs. The access to this service 8 | is offer through an APIRest and all data is transmitted in JSON. 9 | 10 | ![](sbd.png) 11 | 12 | ###### Requirements 13 | 14 | To run this service we need have installed mysql-server engine. This service is thinking to run in Google Cloud Platform, 15 | in [CloudSQL](https://cloud.google.com/sql/) where we only need create the service and connect it 16 | with our program in the same way that in local. 17 | This process is similar an in the both cases we only need use [MySQLdb](http://mysql-python.sourceforge.net/MySQLdb-1.2.2) 18 | python library 19 | To install MySQL engine we can use the script `mysql_install.sh` in this folder (it's only necesary out of GCP). 20 | 21 | Beside this you need execute `requirements.txt` to provide to machine which run this code all libraries that python needs. 22 | 23 | ###### Run 24 | 25 | Finally you can running the api executing the script `run.sh` in this folder. 26 | 27 | If you want, you can provide that data to service executing the provisioner `provisioner.sh`. 28 | 29 | 30 | ###### Documentation: 31 | 32 | This microservice is documented with Sphinx, before you read the doc you need generated it, running `make html` 33 | inside docs folder and then open *index.html* in `build/html` in the same folder, all doc is web based. 34 | 35 | Also **fab doc_dbms** from main folder (firefox required). -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/tdbms/__init__.py -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/appengine_config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from google.appengine.ext import vendor 4 | #Para que entienda que las librerías de terceros debe buscarlas en la carpeta lib 5 | vendor.add('lib') 6 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/README.md: -------------------------------------------------------------------------------- 1 | ##Api de conexión con la base de datos mySQL. 2 | 3 | ![](https://img.shields.io/badge/coverage-42%-green.svg) 4 | 5 | Simplifica las llamadas y gestiones aislándo de la sintaxis de MySQL. 6 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/tdbms/dbapi/__init__.py -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/db_params.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ''' 4 | Fichero que importa la librería para la conexión con MySQL con python. En este también se especifican las 5 | variables de conexión con la BD en el entorno de desarrollo y se define la función conecta que 6 | usan todas los subficheros de la API para conectarse con la base de datos. 7 | ''' 8 | 9 | # Doc here: http://mysql-python.sourceforge.net/MySQLdb-1.2.2/ 10 | import MySQLdb, MySQLdb.cursors 11 | 12 | import os 13 | 14 | # Local DB connection vars. 15 | host = 'localhost' 16 | user = 'root' 17 | password = 'root' 18 | db = 'sms' 19 | 20 | # Variables de conexión a la instancia de Cloud SQL en producción, a partir de un fichero externo. 21 | # El fichero tiene el siguiente contenido: _INTANCE_NAME='your-project-id:your-instance-name' 22 | import productionCloudSQLInstanceINFO as psqlinfo 23 | 24 | 25 | # Método de conexión, que se define de forma que sirva tanto en entorno DEV como en PRODUCCIÓN. 26 | def conecta(): 27 | 28 | if os.getenv('SERVER_SOFTWARE', '').startswith('Google App Engine/'): 29 | return MySQLdb.connect(unix_socket='/cloudsql/' + 'sms-back-end:dbms-db', db=db, user='root', passwd='root', charset='utf8', cursorclass=MySQLdb.cursors.DictCursor) 30 | else: 31 | return MySQLdb.connect(host, user, password, db, charset='utf8', cursorclass=MySQLdb.cursors.DictCursor); 32 | 33 | #Seteando el chartset a utf-8 en la conexión nos ahorramos de tener que establecer esto en cada conexión. 34 | 35 | 36 | ''' 37 | Función extra para codificar el texto de la base de datos que está en utf8 de forma correcta para que pueda imprimirse 38 | por terminal. 39 | ''' 40 | def formatOutputText(cadena): 41 | return cadena.encode('utf-8') 42 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/productionCloudSQLInstanceINFO.py: -------------------------------------------------------------------------------- 1 | _INSTANCE_NAME='sms-back-end:dbms-db' 2 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/test/README.md: -------------------------------------------------------------------------------- 1 | ### Ways to execute tests in **dbapi**: 2 | 3 | 4 | - Inside of **dbapi** package folder. 5 | Only executing `pytest` (it will search all test files). 6 | - Inside of **dbapi** package folder, especify the name of test file inside of tests folder: 7 | `pytest tests/test_sorters.py::test_special_sort_1` 8 | 9 | 10 | - `pytest --cov-report term-missing --cov=. test/` 11 | 12 | - `pytest --pep8` 13 | 14 | 15 | Is not allowed executed test inside of tests folders because the way to import files. -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/test/sorters_tests_files/expected_sorted_list_1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "subject": { 4 | "subjectId": 1, 5 | "name": "Matem\u00e1ticas" 6 | }, 7 | "classes": [ 8 | { 9 | "classId": 7, 10 | "course": 2, 11 | "word": "A", 12 | "level": "Bachillerato", 13 | "impartId": 5 14 | }, 15 | { 16 | "classId": 8, 17 | "course": 2, 18 | "word": "B", 19 | "level": "Bachillerato", 20 | "impartId": 44 21 | }, 22 | { 23 | "classId": 1, 24 | "course": 1, 25 | "word": "A", 26 | "level": "ESO", 27 | "impartId": 141 28 | } 29 | ] 30 | }, 31 | { 32 | "subject": { 33 | "subjectId": 7, 34 | "name": "Franc\u00e9s" 35 | }, 36 | "classes": [ 37 | { 38 | "classId": 4, 39 | "course": 1, 40 | "word": "B", 41 | "level": "Bachillerato", 42 | "impartId": 154 43 | }, 44 | { 45 | "classId": 8, 46 | "course": 2, 47 | "word": "B", 48 | "level": "Bachillerato", 49 | "impartId": 186 50 | } 51 | ] 52 | } 53 | ] -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/test/sorters_tests_files/expected_sorted_list_2.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "class": { 4 | "classId": 7, 5 | "course": 1, 6 | "word": "A", 7 | "level": "ESO" 8 | }, 9 | "subjects": [ 10 | { 11 | "name": "Matemáticas", 12 | "subjectId": 1, 13 | "enrollmentId": 5 14 | }, 15 | { 16 | "name": "Calculo", 17 | "subjectId": 2, 18 | "enrollmentId": 53 19 | }, 20 | { 21 | "name": "Geografia", 22 | "subjectId": 4, 23 | "enrollmentId": 142 24 | }, 25 | { 26 | "name": "Historia", 27 | "subjectId": 1, 28 | "enrollmentId": 59 29 | } 30 | ] 31 | } 32 | ] -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/test/sorters_tests_files/expected_sorted_list_3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "class": { 4 | "classId": 8, 5 | "course": 2, 6 | "word": "B", 7 | "level": "Bachillerato", 8 | "associationId": 9 9 | }, 10 | "teachers": [ 11 | { 12 | "teacherId": 6, 13 | "name": "Enrique", 14 | "impartId": 21 15 | }, 16 | { 17 | "teacherId": 4, 18 | "name": "Blanca", 19 | "impartId": 79 20 | }, 21 | { 22 | "teacherId": 15, 23 | "name": "Carmen", 24 | "impartId": 91 25 | } 26 | ] 27 | }, 28 | { 29 | "class": { 30 | "classId": 5, 31 | "course": 2, 32 | "word": "A", 33 | "level": "ESO", 34 | "associationId": 10 35 | }, 36 | "teachers": [ 37 | { 38 | "teacherId": 4, 39 | "name": "Blanca", 40 | "impartId": 5 41 | }, 42 | { 43 | "teacherId": 1, 44 | "name": "Felipe", 45 | "impartId": 34 46 | } 47 | ] 48 | }, 49 | { 50 | "class": { 51 | "classId": 1, 52 | "course": 1, 53 | "word": "A", 54 | "level": "ESO", 55 | "associationId": 11 56 | }, 57 | "teachers": [ 58 | { 59 | "teacherId": 3, 60 | "name": "Margarita", 61 | "impartId": 7 62 | }, 63 | { 64 | "teacherId": 10, 65 | "name": "Jose Carlos", 66 | "impartId": 40 67 | }, 68 | { 69 | "teacherId": 14, 70 | "name": "Felix", 71 | "impartId": 51 72 | }, 73 | { 74 | "teacherId": 6, 75 | "name": "Enrique", 76 | "impartId": 68 77 | }, 78 | { 79 | "teacherId": 15, 80 | "name": "Carmen", 81 | "impartId": 90 82 | } 83 | ] 84 | }, 85 | { 86 | "class": { 87 | "classId": 4, 88 | "course": 1, 89 | "word": "B", 90 | "level": "Bachillerato", 91 | "associationId": 12 92 | }, 93 | "teachers": [ 94 | { 95 | "teacherId": 9, 96 | "name": "Victor", 97 | "impartId": 27 98 | }, 99 | { 100 | "teacherId": 8, 101 | "name": "Lorena", 102 | "impartId": 46 103 | }, 104 | { 105 | "teacherId": 10, 106 | "name": "Jose Carlos", 107 | "impartId": 67 108 | }, 109 | { 110 | "teacherId": 4, 111 | "name": "Blanca", 112 | "impartId": 81 113 | } 114 | ] 115 | }, 116 | { 117 | "class": { 118 | "level": "Bachillerato", 119 | "word": "A", 120 | "associationId": 24, 121 | "classId": 3, 122 | "course": 1 123 | } 124 | } 125 | ] -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/test/sorters_tests_files/expected_sorted_list_4.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "subject":{ 3 | "subjectId": 2, 4 | "subjectName": "Lengua", 5 | "associationId": 1 6 | }, 7 | "teachers":[ 8 | { 9 | "teacherId": 10, 10 | "teacherName": "Jose Carlos", 11 | "impartId": 60 12 | } 13 | ] 14 | }, 15 | { 16 | "subject": { 17 | "subjectId": 1, 18 | "subjectName": "Matemáticas", 19 | "associationId": 11 20 | }, 21 | "teachers": [ 22 | { 23 | "teacherId": 3, 24 | "teacherName": "Margarita", 25 | "impartId": 7 26 | }, 27 | { 28 | "teacherId": 10, 29 | "teacherName": "Jose Carlos", 30 | "impartId": 40 31 | }, 32 | { 33 | "teacherId": 14, 34 | "teacherName": "Felix", 35 | "impartId": 51 36 | }, 37 | { 38 | "teacherId": 6, 39 | "teacherName": "Enrique", 40 | "impartId": 68 41 | }, 42 | { 43 | "teacherId": 15, 44 | "teacherName": "Carmen", 45 | "impartId": 90 46 | } 47 | ] 48 | }, 49 | { 50 | "subject": { 51 | "subjectId": 6, 52 | "subjectName": "Música", 53 | "associationId": 16 54 | }, 55 | "teachers": [ 56 | { 57 | "teacherId": 7, 58 | "teacherName": "Santiago", 59 | "impartId": 14 60 | }, 61 | { 62 | "teacherId": 4, 63 | "teacherName": "Blanca", 64 | "impartId": 52 65 | } 66 | 67 | ] 68 | }, 69 | { 70 | "subject": { 71 | "subjectId": 4, 72 | "subjectName": "Sociales", 73 | "associationId": 25 74 | }, 75 | "teachers": [ 76 | { 77 | "teacherId": 3, 78 | "teacherName": "Margarita", 79 | "impartId": 16 80 | }, 81 | { 82 | "teacherId": 8, 83 | "teacherName": "Lorena", 84 | "impartId": 44 85 | }, 86 | { 87 | "teacherId": 16, 88 | "teacherName": "Esther", 89 | "impartId": 59 90 | }, 91 | { 92 | "teacherId": 2, 93 | "teacherName": "Francisco Javier", 94 | "impartId": 64 95 | } 96 | 97 | ] 98 | } 99 | ] -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/test/sorters_tests_files/original_list_1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "classId": 7, 4 | "course": 2, 5 | "impartId": 5, 6 | "level": "Bachillerato", 7 | "name": "Matem\u00e1ticas", 8 | "subjectId": 1, 9 | "word": "A" 10 | }, 11 | { 12 | "classId": 8, 13 | "course": 2, 14 | "impartId": 44, 15 | "level": "Bachillerato", 16 | "name": "Matem\u00e1ticas", 17 | "subjectId": 1, 18 | "word": "B" 19 | }, 20 | { 21 | "classId": 1, 22 | "course": 1, 23 | "impartId": 141, 24 | "level": "ESO", 25 | "name": "Matem\u00e1ticas", 26 | "subjectId": 1, 27 | "word": "A" 28 | }, 29 | { 30 | "classId": 4, 31 | "course": 1, 32 | "impartId": 154, 33 | "level": "Bachillerato", 34 | "name": "Franc\u00e9s", 35 | "subjectId": 7, 36 | "word": "B" 37 | }, 38 | { 39 | "classId": 8, 40 | "course": 2, 41 | "impartId": 186, 42 | "level": "Bachillerato", 43 | "name": "Franc\u00e9s", 44 | "subjectId": 7, 45 | "word": "B" 46 | } 47 | ] -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/test/sorters_tests_files/original_list_2.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "classId": 7, 4 | "course": 1, 5 | "word": "A", 6 | "level": "ESO", 7 | "name": "Matemáticas", 8 | "subjectId": 1, 9 | "enrollmentId": 5 10 | }, 11 | { 12 | "classId": 7, 13 | "course": 1, 14 | "word": "A", 15 | "level": "ESO", 16 | "name": "Calculo", 17 | "subjectId": 2, 18 | "enrollmentId": 53 19 | }, 20 | { 21 | "classId": 7, 22 | "course": 1, 23 | "word": "A", 24 | "level": "ESO", 25 | "name": "Geografia", 26 | "subjectId": 4, 27 | "enrollmentId": 142 28 | }, 29 | { 30 | "classId": 7, 31 | "course": 1, 32 | "word": "A", 33 | "level": "ESO", 34 | "name": "Historia", 35 | "subjectId": 1, 36 | "enrollmentId": 59 37 | } 38 | ] -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/test/sorters_tests_files/original_list_3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "level": "Bachillerato", 4 | "teacherId": 6, 5 | "classId": 8, 6 | "name": "Enrique", 7 | "associationId": 9, 8 | "course": 2, 9 | "word": "B", 10 | "impartId": 21 11 | }, 12 | { 13 | "level": "Bachillerato", 14 | "teacherId": 4, 15 | "classId": 8, 16 | "name": "Blanca", 17 | "associationId": 9, 18 | "course": 2, 19 | "word": "B", 20 | "impartId": 79 21 | }, 22 | { 23 | "level": "Bachillerato", 24 | "teacherId": 15, 25 | "classId": 8, 26 | "name": "Carmen", 27 | "associationId": 9, 28 | "course": 2, 29 | "word": "B", 30 | "impartId": 91 31 | }, 32 | { 33 | "level": "ESO", 34 | "teacherId": 4, 35 | "classId": 5, 36 | "name": "Blanca", 37 | "associationId": 10, 38 | "course": 2, 39 | "word": "A", 40 | "impartId": 5 41 | }, 42 | { 43 | "level": "ESO", 44 | "teacherId": 1, 45 | "classId": 5, 46 | "name": "Felipe", 47 | "associationId": 10, 48 | "course": 2, 49 | "word": "A", 50 | "impartId": 34 51 | }, 52 | { 53 | "level": "ESO", 54 | "teacherId": 3, 55 | "classId": 1, 56 | "name": "Margarita", 57 | "associationId": 11, 58 | "course": 1, 59 | "word": "A", 60 | "impartId": 7 61 | }, 62 | { 63 | "level": "ESO", 64 | "teacherId": 10, 65 | "classId": 1, 66 | "name": "Jose Carlos", 67 | "associationId": 11, 68 | "course": 1, 69 | "word": "A", 70 | "impartId": 40 71 | }, 72 | { 73 | "level": "ESO", 74 | "teacherId": 14, 75 | "classId": 1, 76 | "name": "Felix", 77 | "associationId": 11, 78 | "course": 1, 79 | "word": "A", 80 | "impartId": 51 81 | }, 82 | { 83 | "level": "ESO", 84 | "teacherId": 6, 85 | "classId": 1, 86 | "name": "Enrique", 87 | "associationId": 11, 88 | "course": 1, 89 | "word": "A", 90 | "impartId": 68 91 | }, 92 | { 93 | "level": "ESO", 94 | "teacherId": 15, 95 | "classId": 1, 96 | "name": "Carmen", 97 | "associationId": 11, 98 | "course": 1, 99 | "word": "A", 100 | "impartId": 90 101 | }, 102 | { 103 | "level": "Bachillerato", 104 | "teacherId": 9, 105 | "classId": 4, 106 | "name": "Victor", 107 | "associationId": 12, 108 | "course": 1, 109 | "word": "B", 110 | "impartId": 27 111 | }, 112 | { 113 | "level": "Bachillerato", 114 | "teacherId": 8, 115 | "classId": 4, 116 | "name": "Lorena", 117 | "associationId": 12, 118 | "course": 1, 119 | "word": "B", 120 | "impartId": 46 121 | }, 122 | { 123 | "level": "Bachillerato", 124 | "teacherId": 10, 125 | "classId": 4, 126 | "name": "Jose Carlos", 127 | "associationId": 12, 128 | "course": 1, 129 | "word": "B", 130 | "impartId": 67 131 | }, 132 | { 133 | "level": "Bachillerato", 134 | "teacherId": 4, 135 | "classId": 4, 136 | "name": "Blanca", 137 | "associationId": 12, 138 | "course": 1, 139 | "word": "B", 140 | "impartId": 81 141 | }, 142 | { 143 | "level": "Bachillerato", 144 | "word": "B", 145 | "associationId": 9, 146 | "classId": 8, 147 | "course": 2 148 | }, 149 | { 150 | "level": "ESO", 151 | "word": "A", 152 | "associationId": 10, 153 | "classId": 5, 154 | "course": 2 155 | }, 156 | { 157 | "level": "ESO", 158 | "word": "A", 159 | "associationId": 11, 160 | "classId": 1, 161 | "course": 1 162 | }, 163 | { 164 | "level": "Bachillerato", 165 | "word": "B", 166 | "associationId": 12, 167 | "classId": 4, 168 | "course": 1 169 | }, 170 | { 171 | "level": "Bachillerato", 172 | "word": "A", 173 | "associationId": 24, 174 | "classId": 3, 175 | "course": 1 176 | } 177 | ] -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/test/sorters_tests_files/original_list_4.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "subjectName": "Lengua", 4 | "teacherId": 10, 5 | "impartId": 60, 6 | "teacherName": "Jose Carlos", 7 | "associationId": 1, 8 | "subjectId": 2 9 | }, 10 | { 11 | "subjectName": "Matemáticas", 12 | "teacherId": 3, 13 | "impartId": 7, 14 | "teacherName": "Margarita", 15 | "associationId": 11, 16 | "subjectId": 1 17 | }, 18 | { 19 | "subjectName": "Matemáticas", 20 | "teacherId": 10, 21 | "impartId": 40, 22 | "teacherName": "Jose Carlos", 23 | "associationId": 11, 24 | "subjectId": 1 25 | }, 26 | { 27 | "subjectName": "Matemáticas", 28 | "teacherId": 14, 29 | "impartId": 51, 30 | "teacherName": "Felix", 31 | "associationId": 11, 32 | "subjectId": 1 33 | }, 34 | { 35 | "subjectName": "Matemáticas", 36 | "teacherId": 6, 37 | "impartId": 68, 38 | "teacherName": "Enrique", 39 | "associationId": 11, 40 | "subjectId": 1 41 | }, 42 | { 43 | "subjectName": "Matemáticas", 44 | "teacherId": 15, 45 | "impartId": 90, 46 | "teacherName": "Carmen", 47 | "associationId": 11, 48 | "subjectId": 1 49 | }, 50 | { 51 | "subjectName": "Música", 52 | "teacherId": 7, 53 | "impartId": 14, 54 | "teacherName": "Santiago", 55 | "associationId": 16, 56 | "subjectId": 6 57 | }, 58 | { 59 | "subjectName": "Música", 60 | "teacherId": 4, 61 | "impartId": 52, 62 | "teacherName": "Blanca", 63 | "associationId": 16, 64 | "subjectId": 6 65 | }, 66 | { 67 | "subjectName": "Sociales", 68 | "teacherId": 3, 69 | "impartId": 16, 70 | "teacherName": "Margarita", 71 | "associationId": 25, 72 | "subjectId": 4 73 | }, 74 | { 75 | "subjectName": "Sociales", 76 | "teacherId": 8, 77 | "impartId": 44, 78 | "teacherName": "Lorena", 79 | "associationId": 25, 80 | "subjectId": 4 81 | }, 82 | { 83 | "subjectName": "Sociales", 84 | "teacherId": 16, 85 | "impartId": 59, 86 | "teacherName": "Esther", 87 | "associationId": 25, 88 | "subjectId": 4 89 | }, 90 | { 91 | "subjectName": "Sociales", 92 | "teacherId": 2, 93 | "impartId": 64, 94 | "teacherName": "Francisco Javier", 95 | "associationId": 25, 96 | "subjectId": 4 97 | }, 98 | { 99 | "subjectName": "Lengua", 100 | "associationId": 1, 101 | "subjectId": 2 102 | }, 103 | { 104 | "subjectName": "Matemáticas", 105 | "associationId": 11, 106 | "subjectId": 1 107 | }, 108 | { 109 | "subjectName": "Música", 110 | "associationId": 16, 111 | "subjectId": 6 112 | }, 113 | { 114 | "subjectName": "Sociales", 115 | "associationId": 25, 116 | "subjectId": 4 117 | } 118 | ] -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbapi/test/test_sorters.py: -------------------------------------------------------------------------------- 1 | # Run: In the same folder where is folder. 2 | 3 | # pytest test/test_sorters.py -v 4 | 5 | import json, os 6 | import utils as utils 7 | 8 | cwd = os.getcwd() 9 | 10 | def test_special_sort_1(): 11 | 12 | pathA = os.path.join(cwd, "test/sorters_tests_files/original_list_1.json") 13 | pathB = os.path.join(cwd, "test/sorters_tests_files/expected_sorted_list_1.json") 14 | 15 | with open(pathA) as json_data_a: 16 | original = json.load(json_data_a) 17 | 18 | with open(pathB) as json_data_b: 19 | expected = json.load(json_data_b) 20 | 21 | assert utils.sorters.special_sort(original) == expected 22 | 23 | 24 | def test_special_sort_2(): 25 | # To run only: > pytest test.py::test_special_sort_2 26 | 27 | pathA = os.path.join(cwd, "test/sorters_tests_files/original_list_2.json") 28 | pathB = os.path.join(cwd, "test/sorters_tests_files/expected_sorted_list_2.json") 29 | 30 | with open(pathA) as json_data_a: 31 | original = json.load(json_data_a) 32 | 33 | with open(pathB) as json_data_b: 34 | expected = json.load(json_data_b) 35 | 36 | assert utils.sorters.special_sort_2(original) == expected 37 | 38 | 39 | def test_special_sort_3(): 40 | 41 | pathA = os.path.join(cwd, "test/sorters_tests_files/original_list_3.json") 42 | pathB = os.path.join(cwd, "test/sorters_tests_files/expected_sorted_list_3.json") 43 | 44 | with open(pathA) as json_data_a: 45 | original = json.load(json_data_a) 46 | 47 | with open(pathB) as json_data_b: 48 | expected = json.load(json_data_b) 49 | 50 | assert utils.sorters.special_sort_3(original) == expected 51 | 52 | def test_special_sort_4(): 53 | 54 | pathA = os.path.join(cwd, "test/sorters_tests_files/original_list_4.json") 55 | pathB = os.path.join(cwd, "test/sorters_tests_files/expected_sorted_list_4.json") 56 | 57 | with open(pathA) as json_data_a: 58 | original = json.load(json_data_a) 59 | 60 | with open(pathB) as json_data_b: 61 | expected = json.load(json_data_b) 62 | 63 | assert utils.sorters.special_sort_4(original) == expected 64 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/dbms_api_log.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/tdbms/dbms_api_log.log -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/docs/source/APIDB.rst: -------------------------------------------------------------------------------- 1 | NDBlib 2 | =============== 3 | 4 | Librería de abstracción de Cloud Datastore y de su libería de conexión ndb. 5 | 6 | Contents: 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | :name: Librería de acceso a api 11 | 12 | gestorAlumnosSQL 13 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/docs/source/DBMS_API.rst: -------------------------------------------------------------------------------- 1 | DBmS APIRest 2 | =============== 3 | 4 | Connection API 5 | 6 | Contents: 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | dbms_api 12 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/docs/source/anotacionesSQLCloud.md: -------------------------------------------------------------------------------- 1 | La conexión a la instance de SQL Cloud puede realizarse mediante una IP v6 o v4, en caso de ser v6 es gratis pero 2 | el equipo debe poder hacerlo, en este caso no se ha podido y se ha tenido que acceder mediante una v4. Para eso previamente 3 | hay que activar que este tipo de redes puedan conectarse y esto tiene un precio. 4 | 5 | Esta conexión puede realizarse así: 6 | 7 | mysql --host= --user= --password 8 | 9 | Esta conexión es sin SSL y esto tiene sus problemas, pero para empezar puede servir. Además de esta forma 10 | la conexión puede realizarse mediante una Power Shell online. 11 | 12 | 13 | La gestión de la instancia y el acceso a todos los datos se realiza desde la consola cloud de google. 14 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/docs/source/databaseModel.md: -------------------------------------------------------------------------------- 1 | 2 | +-----------------+------------+------+-----+---------+----------------+ 3 | | Field | Type | Null | Key | Default | Extra | 4 | +-----------------+------------+------+-----+---------+----------------+ 5 | | studentId | int(11) | NO | PRI | NULL | auto_increment | 6 | | name | char(50) | YES | | NULL | | 7 | | surname | char(100) | YES | | NULL | | 8 | | dni | int(11) | YES | UNI | NULL | | 9 | | address | char(100) | YES | | NULL | | 10 | | locality | char(50) | YES | | NULL | | 11 | | province | char(50) | YES | | NULL | | 12 | | birthdate | date | YES | | NULL | | 13 | | phone | char(50) | YES | | NULL | | 14 | | profileImageUrl | char(200) | YES | | NULL | | 15 | | createdBy | int(11) | YES | | NULL | | 16 | | createdAt | date | YES | | NULL | | 17 | | modifyBy | int(11) | YES | | NULL | | 18 | | modifyAt | date | YES | | NULL | | 19 | | deletedBy | int(11) | YES | | NULL | | 20 | | deletedAt | date | YES | | NULL | | 21 | | deleted | tinyint(1) | YES | | NULL | | 22 | +-----------------+------------+------+-----+---------+----------------+ 23 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/docs/source/dbms_api.rst: -------------------------------------------------------------------------------- 1 | DBmS Flask APIRest 2 | ================ 3 | 4 | .. automodule:: dbms_api 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/docs/source/gestorAlumnosSQL.rst: -------------------------------------------------------------------------------- 1 | Entities Manager 2 | ================ 3 | 4 | .. automodule:: dbapi.entities_manager 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. MicroServicio Base de Datos documentation master file, created by 2 | sphinx-quickstart on Thu Jun 30 18:09:45 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Teaching DataBase microService documentation! 7 | ======================================================= 8 | 9 | This is bla bla bla 10 | 11 | Contents: 12 | 13 | .. toctree:: 14 | :maxdepth: 2 15 | 16 | tdbms_general 17 | tdbms_api_rest 18 | APIDB 19 | 20 | Indices and tables 21 | ================== 22 | 23 | * :ref:`genindex` 24 | * :ref:`modindex` 25 | * :ref:`search` 26 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/docs/source/tdbms_general.rst: -------------------------------------------------------------------------------- 1 | **General Info** 2 | ======================== 3 | 4 | Imagen de la estructura 5 | 6 | Imagen del modelo de la base de datos. 7 | 8 | Domain 9 | ------------ 10 | 11 | dfdasfkds fsdkfsd fkl sdfk 12 | sdlfjslkfjsdlf 13 | 14 | 15 | Metadata schema 16 | --------------- 17 | - This API Rest work only with JSON data format, to send data and to receive. 18 | - In spite of exists another tables in data model like *Impart*, *Association*, and *Enrollment* that represent different kinds of relations between entities this aren't accessible directly like nested resources from the API, but yes like unique. :: 19 | 20 | ../teacher/n/impart 21 | ... 22 | 400 Bad Request 23 | ... 24 | 25 | 26 | Deleted items storage strategy 27 | ------------------------------ 28 | 29 | We save the deleted item in the same lsdfjsdkalfsd... 30 | 31 | Beside of this we implement -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/img/dbms_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Back-End/tdbms/img/dbms_diagram.png -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/requirements.txt: -------------------------------------------------------------------------------- 1 | # This file install all requirements that python needs in this micro service to run in isolate mode. 2 | # 3 | # Run 'pip install -r requirements.txt -t lib/' to install dependencies in lib/ folder. 4 | # 5 | # Note: The `lib` directory is added to `sys.path` by `appengine_config.py`. 6 | Flask==0.10 7 | Flask-Testing>=0.4.1 8 | flask-cors 9 | unittest2>=0.5 10 | jsonpickle 11 | termcolor 12 | pytz 13 | MySQL-python 14 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/tdbms.yaml: -------------------------------------------------------------------------------- 1 | application: 65748238734626 2 | module: tdbms 3 | version: uno 4 | runtime: python27 5 | api_version: 1 6 | threadsafe: true 7 | 8 | automatic_scaling: 9 | min_idle_instances: 2 10 | max_pending_latency: 1s 11 | 12 | handlers: 13 | - url: /.* 14 | script: tdbms_api.app 15 | 16 | #Especificamos las librerías que queremos usar de las que tienen disponibles en GAE y que no es necesario 17 | #añadir manualmente en /lib, como MySQLdb para la conexión con el la instancia de SQL 18 | libraries: 19 | - name: MySQLdb 20 | version: "latest" 21 | -------------------------------------------------------------------------------- /SMS-Back-End/tdbms/test/README.md: -------------------------------------------------------------------------------- 1 | pytest test/ 2 | 3 | -------------------------------------------------------------------------------- /SMS-Front-End/README.md: -------------------------------------------------------------------------------- 1 | ## UI 2 | 3 | ![License](http://img.shields.io/badge/license-GPLv3-blue.svg) 4 | 5 | **User Interface micro Service** provide SMS web app based user interface 6 | using AngularJS like javascript framework and AngularMaterial like 7 | CSS framework. -------------------------------------------------------------------------------- /SMS-Front-End/app.yaml: -------------------------------------------------------------------------------- 1 | application: your-app-id 2 | version: 1 3 | runtime: python27 4 | threadsafe: true 5 | api_version: 1 6 | 7 | handlers: 8 | 9 | #Manejador para las hojas de estilo 10 | - url: /app 11 | static_dir: app 12 | 13 | - url: /favicon\.ico 14 | static_files: favicon.ico 15 | upload: favicon\.ico 16 | 17 | - url: (.*)/ 18 | #Define la pagina principal que se sirve 19 | static_files: app\1/views/index.html 20 | upload: app 21 | 22 | - url: (.*) 23 | static_files: app\1 24 | upload: app 25 | 26 | -------------------------------------------------------------------------------- /SMS-Front-End/app/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "vendor" 3 | } 4 | -------------------------------------------------------------------------------- /SMS-Front-End/app/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sms-front-end", 3 | "authors": [ 4 | "Juan Antonio " 5 | ], 6 | "version": "0.0.1", 7 | "dependencies": { 8 | "angular": "1.5.8", 9 | "angular-messages": "1.5.8", 10 | "angular-animate": "1.5.8", 11 | "angular-aria": "1.5.8", 12 | "angular-material": "1.1.0", 13 | "angular-material-data-table": "0.9.8", 14 | "angular-resource": "1.4.9", 15 | "moment": "2.11.2", 16 | "angular-moment": "^1.0.0", 17 | "angular-i18n": "^1.6.2", 18 | "angular-ui-router": "^0.4.2", 19 | "highcharts": "^5.0.7", 20 | "mdPickers": "0.7.5" 21 | }, 22 | "resolutions": { 23 | "angular": "1.5.8", 24 | "angular-material": "1.1.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SMS-Front-End/app/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | overflow: hidden; 3 | background-color: #AAAAAA; 4 | } 5 | 6 | md-whiteframe { 7 | background: #fff; 8 | } 9 | 10 | #content { 11 | padding: 24px; 12 | } 13 | 14 | .img-profile-big { 15 | border-radius: 100px; 16 | border: 1px solid #ddd; 17 | display: inline-block; 18 | margin: 4px 16px; 19 | vertical-align: middle; 20 | width: 150px; 21 | } 22 | 23 | .img-profile { 24 | border-radius: 30px; 25 | border: 1px solid #ddd; 26 | display: inline-block; 27 | margin: 4px 16px; 28 | vertical-align: middle; 29 | width: 48px; 30 | } 31 | 32 | .spinner { 33 | margin: 100px auto; 34 | width: 40px; 35 | height: 40px; 36 | position: relative; 37 | } 38 | 39 | .cube1, .cube2 { 40 | background-color: #3F51B5; 41 | width: 15px; 42 | height: 15px; 43 | position: absolute; 44 | top: 0; 45 | left: 0; 46 | 47 | -webkit-animation: sk-cubemove 1.8s infinite ease-in-out; 48 | animation: sk-cubemove 1.8s infinite ease-in-out; 49 | } 50 | 51 | .cube2 { 52 | -webkit-animation-delay: -0.9s; 53 | animation-delay: -0.9s; 54 | } 55 | 56 | @-webkit-keyframes sk-cubemove { 57 | 25% { -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5) } 58 | 50% { -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg) } 59 | 75% { -webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5) } 60 | 100% { -webkit-transform: rotate(-360deg) } 61 | } 62 | 63 | @keyframes sk-cubemove { 64 | 25% { 65 | transform: translateX(42px) rotate(-90deg) scale(0.5); 66 | -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5); 67 | } 50% { 68 | transform: translateX(42px) translateY(42px) rotate(-179deg); 69 | -webkit-transform: translateX(42px) translateY(42px) rotate(-179deg); 70 | } 50.1% { 71 | transform: translateX(42px) translateY(42px) rotate(-180deg); 72 | -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg); 73 | } 75% { 74 | transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5); 75 | -webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5); 76 | } 100% { 77 | transform: rotate(-360deg); 78 | -webkit-transform: rotate(-360deg); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /SMS-Front-End/app/js/main/global.service.js: -------------------------------------------------------------------------------- 1 | angular.module('main') 2 | .directive('spinner', spinnerDirective) 3 | .service("globalService", 4 | function(){ 5 | console.log('Activating globalService service.'); 6 | return { 7 | defaultAvatar : 'https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcThQiJ2fHMyU37Z0NCgLVwgv46BHfuTApr973sY7mao_C8Hx_CDPrq02g', 8 | //defaultMicroServicesURL: 'https://sms-back-end.appspot.com' 9 | defaultMicroServicesURL: 'localhost:8001' 10 | } 11 | } 12 | ); -------------------------------------------------------------------------------- /SMS-Front-End/app/js/main/toast.service.js: -------------------------------------------------------------------------------- 1 | angular.module('main') 2 | .service("toastService", function($mdToast) { 3 | 4 | console.log('Activating toastService service.'); 5 | 6 | var service = { 7 | showToast: showToast 8 | }; 9 | 10 | function showToast(message) { 11 | 12 | var toast = $mdToast.simple() 13 | .content(message) 14 | .position('bottom right') 15 | .hideDelay(3000) 16 | 17 | $mdToast.show(toast); 18 | 19 | }; 20 | 21 | 22 | return service; 23 | 24 | 25 | 26 | } 27 | 28 | ); 29 | -------------------------------------------------------------------------------- /SMS-Front-End/app/js/studentsControl/attendanceControls/attendanceControls.module.js: -------------------------------------------------------------------------------- 1 | // A module without dependencies, with name "teachers" 2 | angular.module('attendanceControls', ['md.data.table']) 3 | .config(function(){ 4 | console.log('Activating attendanceControls module.'); 5 | 6 | }) 7 | 8 | -------------------------------------------------------------------------------- /SMS-Front-End/app/js/studentsControl/attendanceControls/attendanceControls.service.js: -------------------------------------------------------------------------------- 1 | angular.module('attendanceControls') 2 | .factory("attendanceControlsService", 3 | function ($resource, globalService) { 4 | 5 | var restPath = 'http://'+globalService.defaultMicroServicesURL + '/ac/'; 6 | 7 | // The second param is [paramDefaults] to pass param to URL 8 | return $resource(restPath + ':id', {id: '@acId'}, { 9 | 10 | 'getAll': { 11 | method: 'GET', 12 | url: restPath, 13 | isArray: true 14 | }, 15 | 'getBase': { 16 | method: 'GET', 17 | url: restPath + 'base/' + ':id' 18 | } 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /SMS-Front-End/app/js/studentsControl/attendanceControls/attendanceControlsList.js: -------------------------------------------------------------------------------- 1 | angular.module('attendanceControls') 2 | .controller('attendanceControlsListController', function ($scope, $mdDialog, globalService, attendanceControlsService) { 3 | 4 | var vm = this; 5 | 6 | vm.defaultAvatar = globalService.defaultAvatar; 7 | vm.openNewAttendanceControlDialog = openNewAttendanceControlDialog; 8 | 9 | // To control the loading spinner. 10 | vm.dataIsReady = false; 11 | 12 | activate(); 13 | 14 | /////////////////////////////////////////////////////////// 15 | function activate() { 16 | console.log('Activating attendanceControlsListController controller.') 17 | vm.acList = attendanceControlsService.getAll(function () { 18 | vm.dataIsReady = true; 19 | console.log(vm.acList); 20 | }, function (error) { 21 | console.log('Any problem found when was retrieved the attendance controls list.'); 22 | console.log(error); 23 | }) 24 | } 25 | 26 | /** 27 | * Open the floating dialog to create a new attendance control. 28 | */ 29 | function openNewAttendanceControlDialog() { 30 | $mdDialog.show({ 31 | locals: {parentScope: $scope, parentController: vm}, controller: 'newAttendanceControlDialogController', 32 | controllerAs: 'vm', templateUrl: 'app/views/studentsControl/attendanceControls/newAttendanceControlDialog.html' 33 | }).then(function () {}, function () {}); 34 | } 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /SMS-Front-End/app/js/studentsControl/discipline/DisciplinaryNoteOptionCUDDialog.js: -------------------------------------------------------------------------------- 1 | angular.module('discipline') 2 | .controller('newDisciplinaryNoteOptionDialogController', function ($scope, $state, $q, $mdDialog, toastService, parentController) { 3 | 4 | var vm = this; 5 | 6 | vm.title = null; 7 | activate(); 8 | 9 | /////////////////////////////////////////////////////////// 10 | function activate() { 11 | console.log('Activating newDisciplinaryNoteOptionDialogController controller.'); 12 | 13 | vm.mode = parentController.mode; 14 | vm.type = parentController.type; 15 | vm.item = parentController.item; 16 | 17 | 18 | if (parentController.type == 'kind'){ 19 | if (vm.mode == 'create'){ 20 | vm.title = "Añadir tipo"; 21 | vm.subtitle = "Inserte el nombre."; 22 | } 23 | if (vm.mode == 'update'){ 24 | vm.title = "Actualizar tipo"; 25 | vm.subtitle = "Modifique el nombre del tipo." 26 | vm.typeName = vm.item.meaning; 27 | } 28 | } 29 | 30 | 31 | 32 | } 33 | 34 | 35 | vm.closeDialog = function closeDialog() { 36 | $mdDialog.cancel(); 37 | }; 38 | 39 | 40 | vm.saveOption = function saveOption() { 41 | console.log('Calling saveDisciplinaryNote() function.'); 42 | 43 | if(parentController.type == 'kind'){ 44 | 45 | if(vm.mode == 'create') { 46 | 47 | var kinds = parentController.dnSchema.kinds; 48 | var isPosible = true; 49 | for(var a=0; a', 6 | scope: { 7 | config: '=' 8 | }, 9 | link: function (scope, element, attrs) { 10 | var chart; 11 | var process = function () { 12 | var defaultOptions = { 13 | chart: {backgroundColor: null, renderTo: element[0]}, 14 | }; 15 | var config = angular.extend(defaultOptions, scope.config); 16 | chart = new Highcharts.Chart(config); 17 | }; 18 | process(); 19 | scope.$watch("config.series", function (newValue, oldValue) { 20 | console.log('new data received'); 21 | console.log('newValue'); 22 | console.log(newValue); 23 | console.log('oldValue'); 24 | console.log(oldValue); 25 | 26 | process(); 27 | }, true); 28 | scope.$watch("config.loading", function (loading) { 29 | if (!chart) { 30 | return; 31 | } 32 | if (loading) { 33 | chart.showLoading(); 34 | } else { 35 | chart.hideLoading(); 36 | } 37 | }); 38 | } 39 | }; 40 | }; -------------------------------------------------------------------------------- /SMS-Front-End/app/js/teaching/utils/spinnerDirective.js: -------------------------------------------------------------------------------- 1 | var spinnerDirective = function() { 2 | return { 3 | restrict: 'E', 4 | template: '
' 5 | }; 6 | }; -------------------------------------------------------------------------------- /SMS-Front-End/app/views/home.html: -------------------------------------------------------------------------------- 1 |

This is a home page view.

2 | 3 | -------------------------------------------------------------------------------- /SMS-Front-End/app/views/studentsControl/attendanceControls/attendanceControlsList.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 |

Controles de Asistencia

6 |

Todos los controles de asistencia del sistema.

7 | 8 | 9 |
10 | 11 |
12 | 13 |
14 |
15 | 16 |
17 | 19 | add 20 | Nuevo 21 | 22 |
23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 |
31 | 32 |

Aún no se ha realizado ningún control de asistencia.

33 |

¿Desea realizar uno?

34 | 35 |
36 | 37 | Realizar 38 | 39 |
40 | 41 |
42 | 43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | search 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 100 | 101 | 102 | 108 | 109 | 110 | 113 | 114 | 115 | 118 | 119 | 120 | 123 | 124 | 125 | 131 | 132 | 133 | 134 | 135 |
ProfesorClaseAsignaturaEstudiantesFechaVer
87 | 88 |
89 | 90 | 91 |
92 |
93 | {{ ac.teacher.teacherId }} 94 | 95 | {{ ac.teacher.name }} {{ ac.teacher.surname }} 96 |
97 | 98 | 99 |
103 | 104 | {{ ac.association.classs.course }} {{ ac.association.classs.word }} {{ 105 | ac.association.classs.level }} 106 | 107 | 111 | {{ ac.association.subject.name }} 112 | 116 | {{ ac.students }} 117 | 121 | {{ ac.createdAt | date : 'EEEE dd-LLLL-yyyy'}} 122 | 126 | 128 | forward 129 | 130 |
136 |
137 | 138 | 141 | 142 |
143 |
144 | 145 |
146 |
-------------------------------------------------------------------------------- /SMS-Front-End/app/views/studentsControl/discipline/disciplinaryNoteProfile.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 | 7 | Disciplina 8 | 9 |
10 | 12 | keyboard_arrow_left 13 | Atras 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |

Detalles del parte disciplinario

26 | Ref: {{vm.disciplinaryNoteId}} 27 | 28 | 29 |
30 | 31 | 32 |
33 | 34 | 35 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue. 36 | Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus. In sodales 37 | pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec, feugiat ultricies 38 | mi.

39 | 40 | 41 |
42 | 43 | 44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /SMS-Front-End/app/views/studentsControl/discipline/newDisciplinaryNoteOption.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

{{ vm.title }}

6 | {{ vm.subtitle}} 7 | 8 |
9 | 10 | 11 | 12 | 13 |
14 |
El campo es necesario.
15 |
No debe tener más de 20 caracteres.
16 |
17 |
18 |
19 | 20 |
21 | 22 | 23 | 24 | 25 | Cancelar 26 | 27 | 28 | 31 | Añadir 32 | Modificar 33 | 34 | 35 | 36 | 37 |
-------------------------------------------------------------------------------- /SMS-Front-End/app/views/teaching/classes/classesList.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

Grupos

5 |

Todos los grupos del sistema.

6 | 7 |
8 | 9 |
10 | 11 |
12 |
13 | 14 |
15 | 17 | add 18 | Nuevo 19 | 20 |
21 | 22 |
23 | 24 | 25 | 26 | 27 |
28 | 29 |

Aún no se ha creado ningun grupo.

30 |

¿Desea crear uno?

31 | 32 |
33 | 34 | add 35 | Crear 36 | 37 |
38 | 39 |
40 | 41 | 42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | search 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 95 | 96 | 97 | 98 | 99 |
NivelCursoGrupoPerfil
{{ item.level }}{{ item.course }}{{ item.word }} 90 | 92 | forward 93 | 94 |
100 |
101 | 102 | 105 | 106 | 107 | 108 |
109 | 110 |
111 |
112 | 113 |
-------------------------------------------------------------------------------- /SMS-Front-End/app/views/teaching/classes/newClassDialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |

addNueva Grupo

6 | 7 | 8 | close 9 | 10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 | 37 |
38 |
39 |
40 | 41 | 42 | 43 | 44 | Cancelar 45 | 46 | 48 | Guardar 49 | 50 | 51 | 52 | 53 |
-------------------------------------------------------------------------------- /SMS-Front-End/app/views/teaching/students/newStudentDialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |

addNuevo Estudiante

6 | 7 | 8 | close 9 | 10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 |
24 | 25 |
26 | 27 | replay 28 | 29 | 30 | 31 | delete 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 44 | 45 | 46 |
47 | 48 |
49 | 50 | 51 | 52 | 53 | 54 |
55 | 56 | 57 | 58 |
59 | 60 | location_on 61 | 62 | 63 | 64 |
65 | 66 |
67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
79 | 80 | 81 |
82 | 83 | 84 | 87 | 88 | 89 | 90 | 91 | phone 92 | 93 | 94 | 95 | 96 |
97 | 98 | 99 |
100 | 101 | email 102 | 103 | 104 | 105 |
106 | 107 |
108 | 109 | 110 | 111 | 112 |
113 | 114 |
115 |
116 |
117 | 118 | 119 | 120 | 121 | Cancelar 122 | 123 | 125 | Guardar 126 | 127 | 128 | 129 | 130 |
-------------------------------------------------------------------------------- /SMS-Front-End/app/views/teaching/students/studentsList.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

Estudiantes

5 |

Todos los estudiantes del sistema.

6 | 7 |
8 | 9 |
10 | 11 |
12 |
13 | 14 |
15 | 17 | add 18 | Nuevo 19 | 20 |
21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |

Aún no se ha dado de alta a ningún estudiante.

31 |

¿Desea insertar uno?

32 | 33 |
34 | 35 | add 36 | Insertar 37 | 38 |
39 | 40 |
41 | 42 | 43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | search 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 92 | 93 | 94 | 101 | 102 | 103 | 109 | 110 | 111 | 112 | 113 |
EstudiantePerfil
84 | 85 |
86 | 87 | 88 |
89 | 90 | 91 |
95 |
96 | {{ item.email }} 97 | 98 | {{ item.name }} {{ item.surname }} 99 |
100 |
104 | 106 | forward 107 | 108 |
114 |
115 | 116 | 119 | 120 | 121 |
122 | 123 |
124 |
125 | 126 |
-------------------------------------------------------------------------------- /SMS-Front-End/app/views/teaching/subjects/newSubjectDialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |

addNueva Asignatura

6 | 7 | 8 | close 9 | 10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 |
33 |
34 |
35 | 36 | 37 | 38 | 39 | Cancelar 40 | 41 | 43 | Guardar 44 | 45 | 46 | 47 | 48 |
-------------------------------------------------------------------------------- /SMS-Front-End/app/views/teaching/subjects/subjectsList.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

Asignaturas

5 |

Todos las asignaturas del sistema.

6 | 7 |
8 | 9 |
10 | 11 |
12 |
13 |
14 | 16 | add 17 | Nuevo 18 | 19 |
20 |
21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 |

Aún no se ha creado ninguna asignatura.

29 |

¿Desea crear una?

30 | 31 |
32 | 33 | add 34 | Crear 35 | 36 |
37 | 38 |
39 | 40 | 41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | search 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 87 | 88 | 89 | 95 | 96 | 97 | 98 | 99 |
NombrePerfil
81 |
82 | {{ item.email }} 83 | 84 | {{ item.name }} {{ item.surname }} 85 |
86 |
90 | 92 | forward 93 | 94 |
100 |
101 | 102 | 105 | 106 | 107 | 108 |
109 | 110 |
111 | 112 |
113 | 114 | 115 |
-------------------------------------------------------------------------------- /SMS-Front-End/app/views/teaching/teachers/newTeacherDialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |

addNuevo Profesor

6 | 7 | 8 | close 9 | 10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 |
24 | 25 |
26 | 27 | replay 28 | 29 | 30 | 31 | delete 32 | 33 |
34 | 35 |
36 | 37 | 38 |
39 | 40 | 41 | 42 | 43 | 44 |
45 | 46 |
47 | 48 | 49 | 50 | 51 | 52 |
53 | 54 |
55 | 56 | location_on 57 | 58 | 59 | 60 |
61 | 62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 |
75 | 76 |
77 | 78 | 79 | 82 | 83 | 84 | 85 | 86 | phone 87 | 88 | 89 | 90 | 91 |
92 | 93 |
94 | 95 | email 96 | 97 | 98 | 99 |
100 | 101 |
102 | 103 | 104 | 105 | 106 |
107 | 108 |
109 |
110 |
111 | 112 | 113 | 114 | 115 | Cancelar 116 | 117 | 119 | Guardar 120 | 121 | 122 | 123 | 124 |
-------------------------------------------------------------------------------- /SMS-Front-End/app/views/teaching/teachers/teachersList.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 |

Profesores

6 |

Todos los profesores del sistema.

7 | 8 | 9 |
10 | 11 |
12 | 13 |
14 |
15 | 16 |
17 | 19 | add 20 | Nuevo 21 | 22 |
23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 |
31 | 32 |

Aún no se ha dado de alta a ningún profesor.

33 |

¿Desea insertar uno?

34 | 35 |
36 | 37 | add 38 | Insertar 39 | 40 |
41 | 42 |
43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | search 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 93 | 94 | 95 | 102 | 103 | 104 | 110 | 111 | 112 | 113 | 114 |
ProfesorPerfil
85 | 86 |
87 | 88 | 89 |
90 | 91 | 92 |
96 |
97 | {{ item.email }} 98 | 99 | {{ item.name }} {{ item.surname }} 100 |
101 |
105 | 107 | forward 108 | 109 |
115 |
116 | 117 | 120 | 121 |
122 |
123 | 124 |
125 |
-------------------------------------------------------------------------------- /SMS-Front-End/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Front-End/favicon.ico -------------------------------------------------------------------------------- /SMS-Front-End/license.txt: -------------------------------------------------------------------------------- 1 | 2 | 11 | -------------------------------------------------------------------------------- /SMS-Front-End/requirements.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Front-End/requirements.sh -------------------------------------------------------------------------------- /SMS-Front-End/test/geckodriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/SMS-Front-End/test/geckodriver -------------------------------------------------------------------------------- /SMS-Front-End/test/prueba.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from selenium import webdriver 4 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 5 | 6 | """ 7 | browser = webdriver.Firefox() 8 | browser.get('http://www.ubuntu.com/') 9 | """ 10 | from selenium.webdriver.common.keys import Keys 11 | driver = webdriver.Firefox() 12 | 13 | """ 14 | driver.get("http://www.python.org") 15 | assert "Python" in driver.title 16 | elem = driver.find_element_by_name("q") 17 | elem.clear() 18 | elem.send_keys("pycon") 19 | elem.send_keys(Keys.RETURN) 20 | assert "No results found." not in driver.page_source 21 | """ 22 | 23 | driver.get("http://localhost:8080/#/grupos/1") 24 | assert "Python" in driver.title 25 | elem = driver.find_element_by_name("q") 26 | elem.clear() 27 | elem.send_keys("pycon") 28 | elem.send_keys(Keys.RETURN) 29 | assert "No results found." not in driver.page_source 30 | 31 | 32 | driver.close() 33 | #driver.quit() 34 | -------------------------------------------------------------------------------- /dev-requirements.txt: -------------------------------------------------------------------------------- 1 | # Developing requirements for python 2.7 2 | fabric 3 | requests 4 | 5 | -------------------------------------------------------------------------------- /docs/source/DESPLIEGUE.md: -------------------------------------------------------------------------------- 1 | Anotaciones relativas al despliegue: 2 | 3 | 1. Descargar la última versión del SDK de GAE y configurar la cuenta para el proyecto. 4 | 5 | Para hacer el despliegue: 6 | 7 | gcloud app deploy app.yaml --project sms-front-end 8 | 9 | > gcloud app deploy apigms.yaml --project sms-backend 10 | 11 | 12 | gcloud app deploy apigms/apigms.yaml dbms/dbms.yaml --project sms-back-end 13 | 14 | MYSQL 15 | 16 | Después de crear la instancia de MYSQL nos conectamos y creamos nuestra base de datos. -------------------------------------------------------------------------------- /docs/source/branches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/docs/source/branches.png -------------------------------------------------------------------------------- /docs/source/gcloud.md: -------------------------------------------------------------------------------- 1 | Last: --version 2 | 3 | > gcloud --version 4 | Google Cloud SDK 141.0.0 5 | app-engine-python 1.9.49 6 | beta 2016.01.12 7 | bq 2.0.24 8 | bq-nix 2.0.24 9 | core 2017.01.20 10 | core-nix 2016.11.07 11 | gcd-emulator v1beta3-1.0.0 12 | gcloud 13 | gsutil 4.22 14 | gsutil-nix 4.19 15 | 16 | gcloud config configurations list 17 | 18 | NAME IS_ACTIVE ACCOUNT PROJECT DEFAULT_ZONE DEFAULT_REGION 19 | default True butterflydevsmail@gmail.com sms-backend 20 | 21 | 22 | gcloud app browse 23 | 24 | To see the project in the web. 25 | 26 | Para iniciar un nuevo proyecto hacemos gcloud init -------------------------------------------------------------------------------- /docs/source/img/GAE_final_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/docs/source/img/GAE_final_architecture.png -------------------------------------------------------------------------------- /docs/source/img/sms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/docs/source/img/sms.png -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. MicroServicio Base de Datos documentation master file, created by 2 | sphinx-quickstart on Thu Jun 30 18:09:45 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Student Management System 7 | ========================= 8 | 9 | Welcome to **Student Management System** documentation. All that you need to know about the project. 10 | 11 | 12 | Contents: 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | 17 | 18 | 19 | Mainly Subsystems: 20 | 21 | - `Back End`_ 22 | 23 | .. _Back End: file:///home/juan/Documentos/TFG/StudentsManagementSystem/SMS-Back-End/docs/build/html/index.html 24 | 25 | 26 | Indices and tables 27 | ================== 28 | 29 | * :ref:`genindex` 30 | * :ref:`modindex` 31 | * :ref:`search` 32 | 33 | * :ref:`python` 34 | * :ref:`backend` 35 | -------------------------------------------------------------------------------- /provisioner/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ButterFlyDevs/StudentsManagementSystem/827fbfa5fadf24087403d710d476b09ab972538e/provisioner/__init__.py -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # This requirements file lists all third-party dependencies for this project. 2 | # Example of use: 'pip install -r requirements.txt -t lib/' 3 | # Note: The `lib` directory is added to `sys.path` by `appengine_config.py`. 4 | 5 | names 6 | Faker 7 | requests 8 | termcolor 9 | MySQL-python 10 | progressbar 11 | 12 | 13 | -------------------------------------------------------------------------------- /requirements_bash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo -e "\033[32m \n\t ### SMS, a project of \033[35m ButterFlyDevs \033[32m ### \033[0m" 3 | echo -e "\033[32m \n\t Thanks for contributing. \033[0m" 4 | 5 | 6 | echo -e "It will be installed a lot of required software.\n" 7 | 8 | 9 | read -p "Are you sure? [y/n]: " -n 1 -r 10 | echo # (optional) move to a new line 11 | if [[ $REPLY =~ ^[Yy]$ ]] 12 | then 13 | 14 | echo -e "\n\033[32m 1. Installing unzip \033[0m\n" 15 | sudo apt-get install -y unzip 16 | 17 | echo -e "\n\033[32m 2. Installing curl \033[0m\n" 18 | sudo apt-get install -y curl 19 | 20 | echo -e "\n\033[31m 3. Downloading Google App Engine SDK v.1.9.30 \033[0m\n" 21 | curl -O https://storage.googleapis.com/appengine-sdks/featured/google_appengine_1.9.30.zip 22 | 23 | echo -e "\n\033[34m 4. Unzip SDK \033[0m\n" 24 | unzip google_appengine_1.9.30.zip 25 | 26 | echo -e "\n\033[34m 5. Deleting .zip \033[0m\n" 27 | rm google_appengine_1.9.30.zip 28 | 29 | 30 | echo -e "\n\033[31m 6. Instalando MySQL de forma desatendida \033[0m\n" 31 | 32 | sudo apt-get update 33 | sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password root' 34 | sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password root' 35 | sudo apt-get --force-yes -y install mysql-server 36 | 37 | echo -e "\033[31m" 38 | echo "MySQL installation finished" 39 | mysql --version 40 | 41 | 42 | echo -e "\n\033[31m 7. Installing python mysqldb library \033[0m\n" 43 | sudo apt-get install -y python-mysqldb 44 | 45 | echo -e "\n\033[31m 8. Installing python PIP packages manager \033[0m\n" 46 | sudo apt-get install -y python-pip 47 | 48 | echo -e "\n\033[32m ### Dependencies of MICROSERVICES ### \033[0m\n" 49 | 50 | echo -e "\n\033[32m 9. Intalling dependencies of API Gatewary micro Service using pip \033[0m\n" 51 | sudo pip install -r SMS-Back-End/apigms/requirements.txt -t SMS-Back-End/apigms/lib/ 52 | 53 | echo -e "\n\033[32m 10. Intalling dependencies of Teaching Data Base micro Service using pip \033[0m\n" 54 | sudo pip install -r SMS-Back-End/tdbms/requirements.txt -t SMS-Back-End/tdbms/lib/ 55 | 56 | echo -e "\n\033[32m 11. Intalling dependencies of Students Control micro Service using pip \033[0m\n" 57 | sudo pip install -r SMS-Back-End/scms/requirements.txt -t SMS-Back-End/scms/lib/ 58 | 59 | # Info message: 60 | echo "If any part of this automated proccess fail, please review requirementes_bash.sh to know more details about it." 61 | 62 | 63 | else 64 | 65 | echo -e "\n\033[34m :( maybe in another moment \033[0m\n" 66 | 67 | fi 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /utils/count.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Copia del fichero que está en .git/hooks/post-commit para que se ejecute tras hacer un commit en la rama develop. 4 | 5 | rama="$(git branch | sed -n '/\* /s///p')" 6 | echo -e "RAMA actual" ${rama} 7 | 8 | #Para evitar que un commit en cualquier otra rama ejecute el script 9 | if [ "$rama" == "develop" ] 10 | then 11 | #Leemos el número de commit 12 | COMMIT="$(git rev-list --count HEAD)" 13 | #Leemos la fecha 14 | FECHA="$(date +%Y-%m-%d)" 15 | 16 | #Nos movemos al microservicio sce 17 | cd SMS-Back-End/sce 18 | #Leemos todos los ficheros que están en seguimiento, quitamos aquellos con la extensión .png 19 | #después contamos las lineas de todos y cogemos del resultado la primera columna de la última linea, 20 | #que tiene el total de lineas. 21 | # git ls-files | grep -v '\.png' | xargs wc -l | awk 'END{print $1} 22 | #Ejecutamos y guardamos en la variable 23 | LINES_SCE="$(git ls-files | grep -v '\.png' | xargs wc -l | awk 'END{print $1}')" 24 | cd ../.. 25 | 26 | #Nos movemos al microservicio sbd 27 | cd SMS-Back-End/sbd 28 | LINES_SBD="$(git ls-files | grep -v '\.png' | xargs wc -l | awk 'END{print $1}')" 29 | cd ../.. 30 | 31 | #Nos movemos al microservicio apigateway 32 | cd SMS-Back-End/apigateway 33 | LINES_APIG="$(git ls-files | grep -v '\.png' | xargs wc -l | awk 'END{print $1}')" 34 | cd ../.. 35 | 36 | #Nos movemos al front end (en este caso hay muchos directorios que omitir, de loskits js y css) 37 | cd SMS-Front-End 38 | LINES_UI="$(git ls-files | grep -E -v '\.png|app/out|app/css|app/js|app/fonts' | xargs wc -l | awk 'END{print $1}')" 39 | cd .. 40 | 41 | #Mostramos el resumen: 42 | echo -e "Commit: " ${COMMIT} 43 | echo -e "Fecha: " ${FECHA} 44 | echo -e "Lineas UI: " ${LINES_UI} 45 | echo -e "Lineas SCE: " ${LINES_SCE} 46 | echo -e "Lineas SBD: " ${LINES_SBD} 47 | echo -e "Lineas APIG: " ${LINES_APIG} 48 | 49 | #Nos cambiamos de rama 50 | git checkout gh-pages 51 | 52 | 53 | puntoComa=';' 54 | lineaAEscribir=${COMMIT}${puntoComa}${FECHA}${puntoComa}${LINES_UI}${puntoComa}${LINES_APIG}${puntoComa}${LINES_SBD}${puntoComa}${LINES_SCE} 55 | echo ${lineaAEscribir} 56 | #ESCRITURA 57 | echo ${lineaAEscribir} >> lines.txt 58 | 59 | #Commit post ESCRITURA 60 | git commit -am "Mod lines.txt file for commit "${COMMIT}" ." 61 | 62 | echo -e "Contenido de lines.txt" 63 | cat lines.txt 64 | 65 | #Volvemos a la rama de desarrollo 66 | git checkout develop 67 | fi 68 | -------------------------------------------------------------------------------- /utils/counter.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import re 6 | 7 | 8 | os.chdir('SMS-Front-End') 9 | ficherosFrontEnd = [] 10 | linesFrontEnd = 0 11 | for root, dirs, files in os.walk(".", topdown=False): 12 | for name in files: 13 | fullname = os.path.join(root, name) 14 | if not re.match('./app/css|./app/js|./app/out|./app/images|./app/fonts', root) and not re.match('LICENSE|logo.svg', name): 15 | ficherosFrontEnd.append(fullname) 16 | f=open(fullname) 17 | linesFrontEnd = linesFrontEnd + len(f.readlines()) 18 | 19 | os.chdir('../SMS-Back-End') 20 | os.chdir('apigateway') 21 | ficherosapig = [] 22 | linesapig = 0 23 | for root, dirs, files in os.walk(".", topdown=False): 24 | for name in files: 25 | fullname = os.path.join(root, name) 26 | if not re.match('./lib', root) and not name.endswith(('pyc','jpg')): 27 | ficherosapig.append(fullname) 28 | #print fullname 29 | f=open(fullname) 30 | linesapig = linesapig + len(f.readlines()) 31 | 32 | 33 | os.chdir('..') 34 | os.chdir('microservicio1') 35 | ficherossbd = [] 36 | linessbd = 0 37 | for root, dirs, files in os.walk(".", topdown=False): 38 | for name in files: 39 | fullname = os.path.join(root, name) 40 | if not re.match('./docs|./lib', root) and not name.endswith('pyc'): 41 | ficherossbd.append(fullname) 42 | print fullname 43 | f=open(fullname) 44 | linessbd = linessbd + len(f.readlines()) 45 | 46 | os.chdir('..') 47 | os.chdir('sce') 48 | ficherossce = [] 49 | linessce = 0 50 | for root, dirs, files in os.walk(".", topdown=False): 51 | for name in files: 52 | fullname = os.path.join(root, name) 53 | if not re.match('./lib', root) and not name.endswith(('pyc','png')): 54 | ficherossce.append(fullname) 55 | print fullname 56 | f=open(fullname) 57 | linessce = linessce + len(f.readlines()) 58 | 59 | ''' 60 | print 'Tams' 61 | print linesFrontEnd 62 | print linesapig 63 | print linessbd 64 | print linessce 65 | ''' 66 | 67 | 68 | #Extraemos el número del commit 69 | 70 | import subprocess 71 | cmd = "git rev-list --count HEAD" 72 | x = subprocess.Popen(cmd, shell=True, stdout = subprocess.PIPE, stderr=subprocess.PIPE) 73 | out, error = x.communicate() 74 | numCommit=out[:-1] 75 | 76 | #print 'numcommit' +str(numCommit) 77 | 78 | os.system("git checkout gh-pages") 79 | 80 | import datetime 81 | date = datetime.date.today() 82 | line=str(numCommit)+';'+str(date)+';'+str(linesFrontEnd)+';'+str(linesapig)+';'+str(linessbd)+';'+str(linessce) 83 | '''cmd="echo \""+line+"\" >> lines.txt" 84 | print cmd 85 | x = subprocess.Popen(cmd, shell=True, stdout = subprocess.PIPE, stderr=subprocess.PIPE) 86 | out, error = x.communicate() 87 | print out 88 | print error 89 | ''' 90 | os.chdir('../..') 91 | f = open('lines.txt', 'a') 92 | f.write(line+'\n') 93 | f.close() 94 | 95 | os.system("git commit -am \" Commit de actualizacion"+numCommit+" . \"") 96 | 97 | cmd = "git checkout master" 98 | os.system(cmd) 99 | -------------------------------------------------------------------------------- /utils/deployInGAE-SMS-Back-End.sh: -------------------------------------------------------------------------------- 1 | #Para subir los dos submodulos 2 | google_appengine/appcfg.py -A sms-backend update SMS-Back-End/apigateway/apigateway.yaml SMS-Back-End/sbd/sbd.yaml 3 | -------------------------------------------------------------------------------- /utils/deployInGAE-SMS-Front-End.sh: -------------------------------------------------------------------------------- 1 | #La aplicación sería accesible desde: http://sms-front-end.appspot.com/ 2 | google_appengine/appcfg.py -A sms-front-end update SMS-Front-End/ 3 | -------------------------------------------------------------------------------- /utils/mysql_install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to install MySQL Server unattended with 'root' like user and password. 4 | 5 | echo -e "\n\033[31m Installing MySQL-Server unattended. \033[0m\n" 6 | 7 | sudo apt-get update 8 | sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password root' 9 | sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password root' 10 | sudo apt-get --force-yes -y install mysql-server 11 | 12 | echo -e "\033[31m" 13 | echo "Done!" 14 | mysql --version 15 | echo "Run the daemon." 16 | sudo /etc/init.d/mysql start 17 | echo -e "If you have found some problem, try to install this manually." 18 | echo -e "\033[0m" 19 | -------------------------------------------------------------------------------- /utils/mysql_purge.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to delete all about mysql if some problem appear. 4 | 5 | sudo apt-get remove --purge mysql* 6 | sudo apt-get autoremove 7 | sudo apt-get autoclean -------------------------------------------------------------------------------- /utils/tamProyecto.sh: -------------------------------------------------------------------------------- 1 | echo "Para contar las lineas del proyecto" 2 | wc -l `find SMS-Front-End``find SMS-Back-End` 3 | --------------------------------------------------------------------------------