Șef lucrări dr. ing. Marius MARIAN SEPTEMBRIE 2018 CRAIOVA ii UNIVERSITATEA DIN CRAIOVA FACULTATEA DE AUTOMATICĂ, CALCULATOARE ȘI ELECTRONICĂ… [604779]

i

UNIVERSITATEA DIN CRAIOVA
FACULTATEA DE AUTOMATICĂ, CALCULATOARE ȘI
ELECTRONICĂ

DEPARTAMENTUL DE CALCULATOARE ȘI TEHNOLOGIA
INFORMAȚIEI

LUCRARE DE DI SERTAȚIE
DABU Adrian -Florin

COORDONATOR ȘTIINȚIFIC
Șef lucrări dr. ing. Marius MARIAN

SEPTEMBRIE 2018
CRAIOVA

ii

UNIVERSITATEA DIN CRAIOVA
FACULTATEA DE AUTOMATICĂ, CALCULATOARE ȘI
ELECTRONICĂ

DEPARTAMENTUL DE CALCULATOARE ȘI TEHNOLOGIA
INFORMAȚIEI

WEB PLATFORM DEDICATED TO PROMOTING IT ENVIRONMENT TO
ACE STUDENTS: FRONT -END
DABU Adrian -Florin

COORDONATOR ȘTIINȚIFIC
Șef lucrări dr. ing. Marius MARIAN

SEPTEMBRIE 2018
CRAIOVA

iii
„An investment in knowledge pays the best interest .”
Benjamin Franklin

iv
DECLA RAȚIE DE ORIGINALITATE

Subsemnatul DABU ADRIAN -FLORIN , student: [anonimizat], Calculatoare și Electronică a Univers ității din Craiova, certific prin prezenta că am luat la
cunoșt ință de cele prezentate mai jos și că î mi asum, în acest context, originalita tea lucrării mele de
disertație :
 cu titlul WEB PLATFORM DEDICATED TO PROMOTING IT ENVIRONMENT TO ACE
STUDENTS: FRON T-END,
 coordonată de Șef lucrări dr. ing. Marius MARIAN,
 prezentată în sesiunea SEPTEMBRIE 2018.
La elaborarea lucrării de disertație , se consideră plagiat una dintre următoarele acțiuni:
 reproducerea exactă a cuvintelor unui alt autor, dintr -o altă lucra re, în limba română sau prin
traducere dintr -o altă limbă, dacă se omit ghilimele și referința precisă,
 redarea cu alte cuvinte, reformularea prin cuvinte proprii sau rezumarea ideilor din alte
lucrări , dacă nu se indică sursa bibliografică,
 prezentarea unor date experimentale obținute sau a unor aplicații realizate de alți autori fără
menționarea corectă a acestor surse,
 însușirea totală sau parțială a unei lucrări în care regulile de mai sus sunt respectate, dar care
are alt autor.
Pentru evitarea ace stor situații neplăcute se recomandă:
 plasarea într e ghilimele a citatelor directe și indicarea referinței într -o listă corespunzătoare la
sfărșitul lucrării,
 indicarea în text a reformulării unei idei, opinii sau teorii și corespunzător în lista de refe rințe
a sursei originale de la care s -a făcut preluarea,
 precizarea sursei de la care s -au preluat date experimentale, descrieri tehnice, figuri, imagini,
statistici, tabele et caetera ,
 precizarea referințelor poate fi omisă dacă se folosesc informații s au teorii arhicunoscute, a
căror paternitate este unanim cunoscută și acceptată.
Data , Semnătura candidat: [anonimizat] ,

v

UNIVERSITATEA DIN CRAIOVA
Facultatea de Automatică, Calculatoare și Electronică

Departamentul de Calculatoare și Tehnologia Inf ormației
Aprobat la data de
…………………
Șef de departament,
Prof. dr. ing.
Marius BREZOVAN

LUCRARE DE DI SERTAȚIE

Numele și prenumele student: [anonimizat]/ -ei:
DABU Adrian -Florin

Enunțul temei:

Web Platform Dedicated to Promoting IT Environment to
ACE Studen ts: Front -end

Datele de pornire:

Promovarea firmelor IT prin adăugare de articole/anunțuri pe
o singură platforma web, accesibilă tuturor studenților A.C.E

Conținutul lucrării :

1. Introduction
2. Web application – Interface presentation
3. Web applica tion – Implementation
4. Conclu sions
5. Bibliogra phy

Material grafic obligatoriu:
Capturi de ecran
Secvențe de cod

Consultații:
Periodice
Conducătorul științific
(titlul, nume și prenume, semnătura): Șef lucrări dr. ing. Marius MARIAN

Data eliberării te mei:
01.12.201 7

Termenul estimat de predare a
lucrării :
01.06.2018

Data predării lucrării de către student
și semnătura acestuia:
01.09.2018

vi

UNIVERSITATEA DIN CRAIOVA
Facultatea de Automatică, Calculatoare și Electronică

Departamentul de Calculatoare și Tehnologia Informației

REFERATUL CONDUCĂTORULUI ȘTIINȚIFIC

Numele și prenumele candida tului/ -ei: DABU Adrian -Florin
Specializarea: Information Systems for e -Business
Titlul lucrării : Web Platform Dedicated to Promoting IT Environment t o
ACE Students: Front -end
Locația în care s -a realizat practica de
documentare (se bifează una sau mai
multe din opțiunile din dreapta): În facultate □
În producție □
În cercetare □
Altă locație:

În urma analizei lucrării candidatului au fo st constatate următoarele:
Nivelul documentării Insuficient
□ Satisfăcător
□ Bine
□ Foarte bine

Tipul proiectului Cercetare
□ Proiectare
□ Realizare
practică □ Altul

Aparatul matematic utilizat Simplu
□ Mediu
□ Complex
□ Absent

Utilitate Contract de
cercetare □ Cercetare
internă □ Utilare
□ Altul

Redactarea lucrării Insuficient
□ Satisfăcător
□ Bine
□ Foarte bine

Partea grafică, desene Insuficient ă
□ Satisfăcătoare
□ Bună
□ Foarte bună

Realizarea
practică Contribuția aut orului Insuficientă
□ Satisfăcătoare
□ Mare
□ Foarte mare

Complexitatea
temei Simplă
□ Medie
□ Mare
□ Complexă

Analiza cerințelor Insuficient
□ Satisfăcător
□ Bine
□ Foarte bine

Arhitectura Simplă Medie Mare Complexă

vii
□ □ □ □
Întocmirea
specificațiilor
funcționale Insuficientă
□ Satisfăcătoare
□ Bună
□ Foarte bună

Implementarea Insuficientă
□ Satisfăcătoare
□ Bună
□ Foarte bună

Testarea Insuficientă
□ Satisfăcătoare
□ Bună
□ Foarte bună

Funcționarea Da
□ Parțială
□ Nu

Rezultate experimentale Experiment propriu
□ Preluare din bibliografie

Bibliografie Cărți
Reviste
Articole
Referințe web

Comentarii
și
observații

În concluzie, se propune:

ADMITEREA LUCRĂRII
□ RESPINGEREA LUCRĂRII

Data, Semnătura conducătorului științific,

viii
PAPER SUMMARY
This dissertation paper entitled “Web Platform Dedicated to Promoting IT Environment to
ACE Students: Front -end” presents a web application created for the purpose of uniting available
courses, news regarding technologies, training programs, internship positions as well as available job
openings from local It companies as well as companies f rom other cities, in a single, easy to acces
web platform available for the students of the Automation, Computer Science and Electronics Faculty
of Craiova.
It was decided that the best option was to create it as a web application because of how easy
to ac cess web applications are, being available on almost every device that can connect to the internet
such as personal computers, laptops, mobile phones and tablets which is a big advantage over desktop
applications.
There are 3 type of users with different privileges: admin , companies (a representative that is
posting in t he company’s name) and students and the project consists of two modules:
The web app lication (front -end) where all type of users cand enter and access the information
posted by companies a s articles and they can comment on those articles to promote interaction
between the companies and the students (for example: a student posting a question in the comments
and then recieving an answer from a company) . Furthermore, the comments have a scorin g system
based on likes and dislikes (thumbs up/down) that changes the order of the comments, pushing the
most appreciated ones to the top and the most disliked ones to the bottom (for example, an answer to a
popular question regarding that article can re cieve likes and be displayed as a top comment so new
students cand find the answer easier and even without having to post the question beforehand)
The administration panel (back -end) where only the admin and company type of users have
access to. The admin has to approve the creation of new student or company accounts and has full
rights over all application data like manually add ing a student or a company (as opposed to them
registering on their own and waiting for approval from the admin), edit ing informat ion regarding
existent students or companies or simply deleting them if needed and adding, deleting and editing
articles as well. The company can only add and edit or delete existing owned articles from the
administration panel.
The ideea from which this project started was that A.C.E students should have the possibility
to learn about the opportunities and the options available to them once they graduate from this Faculty
and that they can get exposed as early as possible to different technologies so they can experiment and
choose a career in their prefered domain.

Termenii cheie : Forum, It, Companies, Technologies, Students, Opportunities .

ix
Table of contents
1 INTRODUCTION ………………………….. ………………………….. ………………………….. ………………………….. ……. 1
1.1 SCOPE ………………………….. ………………………….. ………………………….. ………………………….. …………………. 1
1.2 MOTIVATION ………………………….. ………………………….. ………………………….. ………………………….. ………… 1
1.3 APPLICATION WORKFLOW ………………………….. ………………………….. ………………………….. ………………………. 1
1.4 USED TECHNOLOGIES ………………………….. ………………………….. ………………………….. ………………………….. .. 2
1.5 APPLICATION ARCHITECT URE ………………………….. ………………………….. ………………………….. …………………… 4
2 WEB APPLICATION – INTERFACE PRESENTATIO N………………………….. ………………………….. ………………. 10
2.1 LOGIN PAGE ………………………….. ………………………….. ………………………….. ………………………….. ………… 10
2.1.1 Register ………………………….. ………………………….. ………………………….. ………………………….. ……….. 10
2.1.2 Forgot password ………………………….. ………………………….. ………………………….. ……………………….. 14
2.1.3 Log out ………………………….. ………………………….. ………………………….. ………………………….. ………… 16
2.2 THE MAIN PAGE ………………………….. ………………………….. ………………………….. ………………………….. ……. 16
2.2.1 The recommended section ………………………….. ………………………….. ………………………….. ………….. 17
2.2.2 The category section ………………………….. ………………………….. ………………………….. ………………….. 18
2.2.3 The tags section ………………………….. ………………………….. ………………………….. ………………………… 19
2.2.4 The search function ………………………….. ………………………….. ………………………….. ……………………. 19
2.3 ARTICLE PAGE ………………………….. ………………………….. ………………………….. ………………………….. ………. 20
2.4 COMPANIES PAGE ………………………….. ………………………….. ………………………….. ………………………….. …. 23
2.5 TRENDING PAGE ………………………….. ………………………….. ………………………….. ………………………….. ……. 24
2.6 ACTIVE STUDENTS PAGE ………………………….. ………………………….. ………………………….. ……………………….. 24
3 WEB APPLICATION – IMPLEMENTATION ………………………….. ………………………….. …………………………. 24
3.1 THE DATABASE ………………………….. ………………………….. ………………………….. ………………………….. ……… 25
3.2 LOGIN PAGE ………………………….. ………………………….. ………………………….. ………………………….. ………… 27
3.2.1 Register ………………………….. ………………………….. ………………………….. ………………………….. ……….. 29
3.2.2 Forgot password ………………………….. ………………………….. ………………………….. ……………………….. 31
3.2.3 Log out ………………………….. ………………………….. ………………………….. ………………………….. ………… 34
3.3 THE MAIN PAGE ………………………….. ………………………….. ………………………….. ………………………….. ……. 35
3.3.1 The recommended section ………………………….. ………………………….. ………………………….. ………….. 38
3.3.2 The categories section ………………………….. ………………………….. ………………………….. ……………….. 40
3.3.3 The tags sectio n ………………………….. ………………………….. ………………………….. ………………………… 41
3.4 ARTICLE PAGE ………………………….. ………………………….. ………………………….. ………………………….. ………. 42
3.5 COMPANIES PAGE ………………………….. ………………………….. ………………………….. ………………………….. …. 52
4 CONCLUSIONS ………………………….. ………………………….. ………………………….. ………………………….. ……. 55

x
5 BIBLIOGRAPHY ………………………….. ………………………….. ………………………….. ………………………….. …… 56
A. SOURCE CODE ………………………….. ………………………….. ………………………….. ………………………….. ……. 57
B. CD / DVD ………………………….. ………………………….. ………………………….. ………………………….. …………… 71

xi
LIST OF FIGURES
FIGURE 1. THE ROOT COMPONENT ………………………….. ………………………….. ………………………….. ………………………….. .. 5
FIGURE 2. ASSETS DIRECTORY ………………………….. ………………………….. ………………………….. ………………………….. …….. 6
FIGURE 3. APPLICATION DIRECTORY ………………………….. ………………………….. ………………………….. ………………………….. 7
FIGURE 4. VIEWS DIRECTORY ………………………….. ………………………….. ………………………….. ………………………….. ……… 8
FIGURE 5. HELPERS DIRECTORY ………………………….. ………………………….. ………………………….. ………………………….. …… 9
FIGURE 6. LOGIN PAGE ………………………….. ………………………….. ………………………….. ………………………….. …………… 10
FIGURE 7. REGISTER PAGE ………………………….. ………………………….. ………………………….. ………………………….. ……….. 11
FIGURE 8. REGISTRATION MAIL NOT IFICATION ………………………….. ………………………….. ………………………….. …………….. 11
FIGURE 9. STUDENT AWAITING APPR OVAL ………………………….. ………………………….. ………………………….. …………………. 12
FIGURE 10. STUDENT APPROVED ………………………….. ………………………….. ………………………….. ………………………….. .. 12
FIGURE 11. REGISTRATION EMAIL ………………………….. ………………………….. ………………………….. ………………………….. . 13
FIGURE 12. ENTER PASSWORD TO COM PLETE REGISTRATION ………………………….. ………………………….. ………………………… 13
FIGURE 13. FORGOT PASSWORD PAGE ………………………….. ………………………….. ………………………….. ……………………… 14
FIGURE 14. FORGOT PASSWORD EMAIL NOTIFICATION ………………………….. ………………………….. ………………………….. …… 14
FIGURE 15. FORGOT PASSWORD EMAIL ………………………….. ………………………….. ………………………….. …………………….. 15
FIGURE 16. ENTER NEW PASSWORD SC REEN ………………………….. ………………………….. ………………………….. ………………. 15
FIGURE 17. MAIN PAGE : LATEST ARTICLE ………………………….. ………………………….. ………………………….. ………………….. 16
FIGURE 18. MAIN PAGE : OLDER ARTICLES ………………………….. ………………………….. ………………………….. ………………….. 17
FIGURE 19. POPULAR ARTICLES ………………………….. ………………………….. ………………………….. ………………………….. …. 17
FIGURE 20. RECOMMENDED SECTION ………………………….. ………………………….. ………………………….. ………………………. 18
FIGURE 21. CATEGORIES ………………………….. ………………………….. ………………………….. ………………………….. …………. 18
FIGURE 22. TAGS ………………………….. ………………………….. ………………………….. ………………………….. …………………. 19
FIGURE 23. SEARCH BAR ………………………….. ………………………….. ………………………….. ………………………….. …………. 19
FIGURE 24. ARTICLE PAGE TITLE AN D BANNER ………………………….. ………………………….. ………………………….. …………….. 20
FIGURE 25. ARTICLE PAGE CONTENT ………………………….. ………………………….. ………………………….. ………………………… 20
FIGURE 26. ARTICLE PAGE TEXT FOR MAT ………………………….. ………………………….. ………………………….. …………………… 21
FIGURE 27. YOUTUBE VIDEO PLAYER ………………………….. ………………………….. ………………………….. ……………………….. 21
FIGURE 28. NATIVE VIDEO PLAYER ………………………….. ………………………….. ………………………….. ………………………….. 22
FIGURE 29. COMMENTS SECTION ………………………….. ………………………….. ………………………….. ………………………….. . 22
FIGURE 30. COMPANIES PAGE ………………………….. ………………………….. ………………………….. ………………………….. …… 23
FIGURE 31. ARTICLES PER COMPANY ………………………….. ………………………….. ………………………….. ……………………….. 24
FIGURE 32. THE DATABASE ………………………….. ………………………….. ………………………….. ………………………….. ………. 25
FIGURE 33. ARTICLE COMMENTS TABL E ………………………….. ………………………….. ………………………….. ……………………. 51
FIGURE 34. COMPANY TABLE ………………………….. ………………………….. ………………………….. ………………………….. ……. 54

xii
LIST OF TABLES
TABLE 1. THE DATABASE ………………………….. ………………………….. ………………………….. ………………………….. …………. 27
TABLE 2. CATEGORIES TABLE ………………………….. ………………………….. ………………………….. ………………………….. …….. 41
TABLE 3. TAG TABLE ………………………….. ………………………….. ………………………….. ………………………….. ………………. 42
TABLE 4. ARTICLE TABLE ………………………….. ………………………….. ………………………….. ………………………….. …………. 44
TABLE 5. ARTICLE COMMENTS TABL E ………………………….. ………………………….. ………………………….. ……………………….. 52
TABLE 6. COMPANY TABLE ………………………….. ………………………….. ………………………….. ………………………….. ………. 54

1
1 INTRODU CTION
1.1 Scop e
The scope of this dissertatio n project is to promote interaction between companies and students
by having a web platform where as a company you can post about training programs and internships
to better prepare students and introduce them to a workplace environment so they can become
employees , and as a student you a re exposed to different technologies and you can decide what you
want to pursue in the future and, hopefully, start your career at one of the companies present on the
app.
1.2 Motiva tion
Students, especially 1st year students , can be overwhelmed by the ammount of technologies and
option s existing in the It domain. If the faculty helps them decide what technology they like the most
and wish to learn, the only problem remains in finding a company to hire them without previous work
experience . I’ve created this application to address that issue by allowing companies to help students
interested in hiring with training courses and internships until they have the necessary skills to
become valuable employees.
1.3 Application workflow
The Forum A.C.E. Application is divided into two modules: a management / back -end one and
a presentation / front -end one.
The back -end is accessible to both the administrator and the companies. This does not mean,
however, that the same category of users have t he same rights. Administrator, of course, has full
rights over all application data, starting wit h the approval of new companies or students wishing to
join this forum and even deleting articles . On the other hand, companies only have editing / deleting
rights on their own articles.
The front -end is equally accessible to both students and companies. Here, students can view
articles posted by companies based on certain filters (the most recent articles, most popular articles,
articles that are tagged with th e same tags or categories as the student originally viewed) . At the same
time, students can add comments on these articles. The comment system is quite complex, with three –
level nested comments (comment => answer => response to the original response) and being featured
with a reviewing feature (like / dislikes can be added and, again depending on their number, the
comm ent will climb or drop down to the level they are in.)

2

1.4 Used technologies
In the web domain, there are two great concepts – client and ser ver. The client or web browser
is the terminal where the user receives the information served by the server through a protocol. Most
commonly used is the Hypertext Transfer Protocol (HTTP) protocol.
The application of this dissertation works on both the cl ient a nd the server. Therefore, a series
of main and secondary technologies (somewhat complementing the main features) that run on both
the client and the server have been used.
For the client side, the following technologies are used:

 HTML 5 – HTML or Hy per Text Markup Language is the standard language for displaying
web pages. It is a markup language because it uses bookmarks / tags to store / organize /
display the information to the client / browser. Version 5 is currently the latest language
version, offering far more features for today's technologies .
 CSS 3 – CSS or Cascade Style Sheet is the language that handles the design of HTML
elements / tags. The latest version, 3, offers many features compared to the previous
version, most of which are found o n the mobile market segment (smartphone / tablet
browsers).
 JavaScript – is the standard web scripting language. Scripts produce actions that allow for
better interaction of the user with the website. Like HTML and CSS, JavaScript runs
directly into the br owser so all three of these languages do not require external libraries /
dependencies.
 jQuery – jQuery is one of the most popular client -side JavaScript frameworks. With this
framework, the DOM Objects (Document Object Model) can be manipulated very eas ily
using the CSS syntax (# for id and class for classes). The version used is 1.11, this being
the most stable at this time.
 Bootstrap – Bootstrap i s another framework, but it is for design purposes. Using CSS3 for
design and jQuery for functionalities. I t is one of the most popular frameworks of its kind
at this time, thanks to well -defined classes, easy -to-use functionalities, and especially for
responsive design (the elements of the web page are folded so that they appear well both on
a resolution compu ter and mobile resolution – smartphone or tablet). Both the management
panel and the teaching staff panel are 100% accomplished within this framework. The
source of the administration panel is https://colorlib.com/polygon/elaadmin/index.html and

3
the front end is https://www.themeineed.com/downloads/bravana -lite-free-bootstrap –
business -template
 Froala Editor – A very important plugin is the WYSIWYG publisher (What You See Is
What You Get) that is used to add items to companies in back -end / backoffice. This editor
is a very complex one, with a huge number of JS and CSS dependencies. In addition to the
front side, it also had to be configured on the server side to be able to add / delete files
directly on the server.
 Other JavaScript plugins: jQuery nicescrol l, jQuery timepicker, select2, jQuery
metisMenu, jQuery slimscroll, screenfull + related CSS files. These plug -ins are related to
the design of certain elements and a better user experience on the site.

For the server side, the following technologies were used:

 PHP – PHP: Hypertext Preprocessor is one of the most popular / popular scripting
languages on the server in the world. Why? Because it is open -source (anyone can
contribute to its development) so it's free, it has a very large and active communit y, it runs
directly on the server and its download and installation is very fast. This language is the
primary rival of scripting language on ASP.net (Microsoft).
 CodeIgniter – CodeIgniter is perhaps the most popul ar lightweight PHP framework. It has
very few dependencies and his installation is very fast. Although it does not compare to the
most famous and performing PHP frameworks – Laravel / Symfony, this framework is very
good and popular on its niche / segment, that is for small applications, maybe eve n
mediums at times.

MySQL has been used as the DBMS (Database Management System). It is the most popular
open -source relational database DBMS, currently available.
To work with PHP and MySQL, the XAMPP environment (Apache + Maria DB + PHP + Perl)
was inst alled. This is a popular platform for developing a project in the Windows operating system, a
project that uses PHP and MySQL. Practically, using this deployment environment, an offline server
is configured on its own computer with Apache (the most popular / used open source HTTP server in
the world). At the same time, PHP, MySQL and a database management system called PHPMyAdmin
are also installed in this environment. This platform allows us to create and run a web application that
uses PHP and MySQL.

4

As an integrated software development environment, PhpStorm was used. This is a very
powerful IDE on PHP but also on the other client -side technologies mentioned above.
Google Chrome (together with Developer Tools) and Mozilla Firefox (along with Firebug)
have been used to test the app.
Last but not least, the Adobe Photoshop software was used to create background images for
login pages and to modify the faculty logo for both the administration panel and the teacher panel.

1.5 Application architecture
The app lication uses MVC (Model View Controller) as the programming style. MVC is a model
/ type of architecture used in software engineering. It is used very often in production, this being
somewhat the standard for web programming but also standalone. The most popular PHP frameworks
(Symfony, Laravel, Zend, PHP Cake) use it but not only. Of course, this pattern is also used by
CodeIgniter.
This type of code approach enjoys this success due to the isolation of the main logic (database
interactio n, more complex op erations) from the user interface, and the data from it is processed to
another level. So each of these three levels has a well established role. Generally, the view takes the
user information and sends it to the controller. It delivers it to the model, wh ich processes it and
resubmits to the controller the final processed information. The latter delivers it to the viewer / user.
This logic separates by level, the controller being the one delivering in the two parts while the model
never communicates with t he view.
The following figures will illustrate the composition of the root / main directory and related
subdirectories.

5

Figure 1. The root component

Code Igniter has, as can be seen above, a fairly simple structure. At the root level, it has
index.php (the application startup file that loads all of the required files for the project) along with
some other files that include composer.json (here are the external dependencies of the framework that
are brought by Composer the most p opular dependency manager for PHP) and .htaccess (a
configuration file on Apache -running servers, at the root level, various server -specific settings can be
modified in this file).
In addition to index.php, CI (CodeIgniter) also has 3 directories (applicat ion, system,
user_guide). The application develops a new application, while the system contains the files that make
up the core CI; (so the developer of the new application only works inside the application directory –
Figure 3). user_guide, as we know fro m the name, contains a user guide for the developer of the new
application. assets, on the other hand, is a directory created by myself that contains the client / front
endings that the application needs to work (JavaScript, CSS, images, fonts – Figure 2).

6

Figure 2. Assets directory
In the application directory, you find the entire code for this application. It is divided into several
subfolders, each of which has a certain importance in the economy of the entire application (Figu re 3).

7

Figure 3. Application directory

The directories that interested me in writing the application are: controllers, models, views,
config, helpers, third_party.
As mentioned above, the architecture / design pattern of the app lication is MVC. But, like all
MVCs, this is also a custom one. Custom in the idea that the relationship between the three
components is not 1: 1: 1. I decided not to go on the idea of 1: 1: 1 because the application is quite
small and because much logic used on back -end is applied on the front end and vice versa. And if I
went to a controller for a model for a view, it would invariably result in a lot of duplicate code, the
DRY (Do not Repeat Yourself) principle, one of the most important programming, no longer
respected. Moreover, some controllers, due to their increased complexity, have several views. This
structure can be seen in Figure 4

8

Figure 4. Views directory

9
The other folders, config, helpers, third_party are folders co ntaining either project configurations
(config contains the routes.php – the place where the application's routes are defined for both admin
and front and database.php – the place where they are defined credentials for database access) but also
non-project -specific functions / plugins / classes that have a specific purpose (PHPMailer – the PHP –
special class for sending mail via SMTP – Simple Mail Transfer Protocol, Editor Editor – sdk /
external library that integrates the Frola editor with the application' s server side). These guidelines can
be seen in Figure 5.

Figure 5. Helpers directory

10
2 WEB APPLICATION – INTERFACE PRESENTATI ON
În this section I will present the interface of each page and its sections as well as their
functional ities.

2.1 Login page

Figure 6. Login Page
When first accessing the website via any link, if the user has not previously logged in, he/she
will be prompted to the login page
.
2.1.1 Register
If the user does not have an account, he/she can click the register button “ Inregistrare ” and will
be redirected to the following screen

11

Figure 7. Register page
At the “Creeare cont” screen, the user has to insert a first name, last name and a valid email
address and clic k the “Inregistrare” button. The user will then be redirect to the login page and a
notification will appear on the top of the screen with a message saying that soon the user will receive
an email with instructions to complete the registration process.

Figure 8. Registration mail notification
Next, the admin has to approve the creation of the user’ s account from the administration panel
and the user will not receive the email to complete the registration process until the admin ap proves
that account by clicking the approve button

12

Figure 9. Student awaiting approval

As seen above, the admin can see in the administration process what students have recently
registered and are awaiting approval. Once the adm in approves a student registration, the status of the
student changes from pending to approved:

Figure 10. Student approved
After approval, the student receives an email with a token (confirmation link) to co mplete the
registrati on process

13

Figure 11. Registration email
After clicking the link, the user is taken to the next screen:

Figure 12. Enter password to complete registration
Here the user can insert a password, insert it again for confirmation and then after clicking the
create account button, he/she is redirected to the main page.

14
2.1.2 Forgot password
If the user has previously created an account but doesn’t remember the password anymore
he/she can click the forgot password bu tton “ aici” which will redirect to the following screen

Figure 13. Forgot password page
Here, the user is asked to insert the email address used when the account was created so user
can receive a new email with a link

Figure 14. Forgot password email notification
After the user insets the email address he/she will be redirect to the login page and a
notification will appear on screen saying that the email with instructions to reset the password has
been sent

15

Figure 15. Forgot password email
Clicking the link in the email will redirect the user to a new page where he/she can enter a
new password and enter it again to confirm it

Figure 16. Enter new pas sword screen
After inserting the new password twice, the user will be redirected to the main page.

16
2.1.3 Log out
The log out button is included in the menu which appears on every page so the user can log out
at any given time by clicking it and then be redirecte d to the login screen.

2.2 The main page
After a successful login, the user will be redirected to the main page, also known as the
„Noutati” page:

Figure 17. Main page: latest article
On the main page, the latest article will alway s be displayed first and occupy more space on
the page, followed by articles based sorted by add date (thew newer the article, the higher the position
on the page).

17

Figure 18. Main page: older articles
Each article on the main p age will have a banner, title, author, add date and a link „Vezi
postare!”. The banner will also have the same link, redirecting to its individual article page.
Below the articles there will be a „Popular” section, displaying the 4 most viewed (or visited )
articles:

Figure 19. Popular articles

2.2.1 The recommended section
Users receive recommendations of articles which may be of interest to them based on previous article
views:

18

Figure 20. Recommended sectio n

2.2.2 The category section
Users have the option to filter articles based on which categories:

Figure 21. Categories
When a category is being hovered, it will turn green indicating that it is clickable and each
category displays th e number of articles included in that category. If there’s no number it means that

19
there is just one article or none at all in that category. Only an admin or the company that posted the
article can add, edit or delete a category from that article.

2.2.3 The tags section
Categories are usefully but when users want to search articles for specific info that may not be
covered in of the categories and they don’t know the title of what they are looking for so they can’t
use the search function, they have the optio n to sort by tags which can be more customizable and
better suit some articles.

Figure 22. Tags
When hovered tags will turn green. Only an admin or the company that posted the article can
add, edit or delete a tag from that artic le but companies can also create new tags.
2.2.4 The search function
Users can search one or more key words to return specific articles:

Figure 23. Search bar
A placeholder text is put in place to better appeal to the users.

20
2.3 Article p age
Each article will have a individual page where the company can post text, upload images,
clickable urls, embedded video from other web sources or upload a video from their computer.

Figure 24. Article page title and banner

At the top of the article page is the title and under it, the author, add date and number of
comments will be displayed.

Figure 25. Article page content

21
There is no limit to the ammount of text, images or videos an article can co ntain.

Figure 26. Article page text format
Companies have the option to format the text in any way they like.

Figure 27. YouTube video player

Embedded videos from YouTube run directly in the article page and the full screen option is
allowed.

22

Figure 28. Native video player

Additionally, videos can be uploaded from the article auth or’s computer and the video player
allows for muting and turning on full screen.
At the end of the article users can see which tags have been assign ed to the article by the author
and the comments section:

Figure 29. Comments se ction
Comments are intended to increase the interaction between students and companies, for
example if a student meets a problem or something unclear regarding a training problem he/she can
ask in the comments section and receive an answer from the company representative or other students

23
whom know the answer. Comments also have a scoring system based on like and dislikes. Likes move
the comment further to the top until it becomes top comment and this was intended for example if
someone comments something r eally useful and this way it becomes more visible to everyone and
dislikes have the opposite effect, moving comments down.
Author of the comments cannot score their own comments and everyone can score a comment
only once and if you score it with both a li ke and a dislike it will cancel out the previous score and
keep only the last. Authors of the comments can always edit them and they can delete them only if it
has no child comments yet.
2.4 Companies page
Users can visit the companies page where they can find all the partner companies that have
accounts on the web application where each company will have a banner with the logo and a
description for the students to read.

Figure 30. Companies page
Here, the user can click on a company to open a page with all of that company’s articles sorted
by date.

24

Figure 31. Articles per company

2.5 Trending page
The trending page will always display popular articles . There will be a list of trending artic les
where the position of each article is determined by how many combined views and comments that
article has gathered.
2.6 Active students page
Following the same principle as the trending page, we want to reward active students, especially
those that display interest in companies and their articles. For this purpose, the active students page
exists, where the students will be displayed based on the combined number comments and comments
reviews.

3 WEB APPLICATION – IMPLEMENTATION
In this section I will present how each page was implemented and explain the functionalities
alongside important snippets of code.

25
3.1 The database
The database is administrated through phpMyAdmin which is a database management system
installed in the XAMPP environment. This system allow s us to create and run a web application that
uses PHP and MySQL. The database has the following tables:

Figure 32. The database

26
Following is a list of the tables in the database alongside a description of each one:
Table name Description
article The main table where we store articles and
information about them.

article_category The table where we assign articles to specific
categories .

article_comment The table where we store comments and
information about them .

article_co mment_thumb The table where we manage the thumbs up or
downs of each comment .

article_tag The table where we assign tags to articles .

article_view The table where we track how many views an
article gets.

backend_user The table with the hardcoded admi n user.

category The table where we store and manage categories.

company The table where we store companies and specific
information regarding them.

student The table where we store students and
information about them.

student_reputation The table where we track how many thumbs up
or downs a student has received.

tag The table where we store and manage tags.

27
tokens The table where we store tokens for user
registration.

Table 1. The database
3.2 Login page
As stated at in th e 2.1 section of this paper, every user must first login before gaining access to
the web application.
When the user inputs data in both the email form and the password form and it is validated, the
form will close and the user will be redirected to the „ Noutati” page (the main page). The login page
php code for the two forms (email and password) from the login.php file is:

<div class="col-lg-4 col-lg-offset-4">
<h2>Forum A.C.E. </h2>
<?php $fattr = array('class' => 'form-signin');
echo form_open (site_url ().'login', $fattr); ?>
<div class="form-group">
<?php echo form_input (array(
'name'=>'email',
'id'=> 'email',
'placeholder' =>'Email',
'class'=>'form-control' ,
'value'=> set_value ('email'))); ?>
<?php echo form_error ('email') ?>
</div>

<div class="form-group">
<?php echo form_password (array(
'name'=>'password' ,
'id'=> 'password' ,
'placeholder' =>'Parola',
'class'=>'form-control' ,
'value'=> set_value ('password' ))); ?>
<?php echo form_error ('password' ) ?>
</div>
<?php echo form_submit (array('value'=>'Log in!' ,
'class'=>'btn btn -lg btn-primary btn -block')); ?>
<?php echo form_close (); ?>
<h5>Ai uitat parola? Click <a href="<?php echo
site_url ();?>forgot">aici</a></h5>
<h5>Nu ai cont? <a href="<?php echo
site_url ();?>register" >Inregistrare </a></h5>
</div>

The session and vali dation rules are in the Front_main.php file:

public function login()
{

28
// if somehow the user is logged but he's accessing the l ogin page,
redirect him to home page
if (!empty($this->session->userdata ['front_id' ])) {
/*go to home page*/
redirect (site_url () . 'acasa');
}

$this->form_validation ->set_rules ('email', 'Email',
'required|va lid_email' );
$this->form_validation ->set_rules ('password' , 'Password' ,
'required' );

if ($this->form_validation ->run() == FALSE) {
$this->load->view('login');
} else {
$post = $this->input->post();
$clean = $this->security ->xss_clean ($post);

$userInfo = $this->user_model ->checkLogin ($clean, $this-
>usersTable , true);

if (!$userInfo ) {
$this->session->set_flashdata ('flash_message' , 'The login
was unsuccessful ');
redirect (site_url () . 'login');
}
foreach ($userInfo as $key => $val) {
$this->session->set_userdata ('front_' . $key, $val);
}
redirect (site_url () . 'acasa');
}
}

And the checkLogin function called in the function above is in the User_model.php file:

public function checkLogin ($post, $usersTable , $frontLogin = false)
{
$this->load->library('password' );
$this->db->select('*');
$this->db->where('email', $post['email']);
$query = $this->db->get($usersTable );
$userInfo = $query->row();
// if front login, login company as well
if (!$userInfo && $frontLogin ) {
$this->db->select('*');
$this->db->where('email', $post['email']);
$query = $this->db->get('company' );
$userInfo = $query->row();
}

if ($userInfo ) {
if (!$this->password ->validate_password ($post['password' ],
$userInfo ->password)) {
log_message ('error','Unsuccessful login attempt(' .
$post['email'] . ')');
return false;
}

29

$this->updateLoginTime ($userInfo ->id, $usersTable );

unset($userInfo ->password );
return $userInfo ;
}

return false;
}
3.2.1 Register
At the login page, the registration link is right under the sign in form and the php code is in
the login.php file:
<h5>Ai uitat parola? Click <a href="<?php echo site_url ();?>forgot"> aici
</a></h5>
Which then, redirects to the registration form with the following code in the register.php file:
<div class="col-lg-4 col-lg-offset-4">
<h2>Creare cont </h2>
<?php
$formAttr = array('class' => 'form-signin');
echo form_open (base_url () . 'register' , $formAttr ); ?>
<div class="form-group">
<?php echo form_input (
array(
'name'=>'lastname' ,
'id'=> 'lastname' ,
'placeholder' =>'Nume',
'class'=>'form-control' ,
'value'=> set_value ('lastname' )
)); ?>
<?php echo form_error ('lastname' );?>
</div>
<div class="form-group">
<?php echo form_input (
array(
'name'=>'firstname' ,
'id'=> 'firstname' ,
'placeholder' =>'Prenume' ,
'class'=>'form-control' ,
'value' => set_value('firstname' )
)); ?>
<?php echo form_error ('firstname' );?>
</div>
<div class="form-group">
<?php echo form_input (
array(
'name'=>'email',
'id'=> 'email',
'placeholder' =>'Email',
'class'=>'form-control' ,
'value'=> set_value ('email')
)); ?>

30
<?php echo form_error ('email');?>
</div>
<?php echo form_submit (array('value'=>'Inregistrare' ,
'class'=>'btn btn -lg btn-primary btn-block')); ?>
<?php echo form_close (); ?>
</div>
The block of code from above saves the user data and closes the form after the user clicks the
submit button (“Inregistrare”) and then, in the Front_main.php file the data validation occurs:
public function register ()
{
$this->form_validation ->set_rules ('firstname' , 'First Name' ,
'required' );
$this->form_validation ->set_rules ('lastname' , 'Last Name' ,
'required' );
$this->form_validation ->set_rules('email', 'Email',
'required|valid_email' );

if ($this->form_validation ->run() == FALSE) {
$this->load->view('register' );
} else {
if ($this->user_model ->isDuplicate ($this->input->post('email'),
$this->usersTable )) {
$this->session->set_flashdata ('flash_message' , 'User email
already exists' );
redirect (site_url () . 'login');
} else {

$clean = $this->security ->xss_clean ($this->input-
>post(NULL, TRUE));
$this->user_model ->insertUser ($clean, $this->usersTable );

$this->session->set_flashdata ('flash_message' , 'In curand
veti primi un email cu instructiuni pentru incheierea procesului de
inregistrare.' );
redirect (site_url () . 'login');
/*$token = $this ->user_model ->insertToken($id, $this –
>usersTable);

$qstring = $this ->base64url_encode($token);
$url = site_url() . 'main/complete/token/' . $qstring;
$link = '<a href="' . $url . '">' . $url . '</a>';

$this->send_register_mail($this ->input->post('email'),
$link);
exit;*/
};
}
}

31
3.2.2 Forgot password
When a user happens to forget the password he/she can a ccess the link below the sign in form
which is in the login.php file and has the following code:
<h5>Ai uitat parola? Click <a href="<?php echo site_url ();?>forgot"> aici
</a></h5>
The user will be prompted to insert the account email so he/she can recieve an email with a
link:
protected function send_forgot_pass_email ($to_email , $link)
{
$from = 'admin@ace.ro' ;
$subject = 'Resetare parola' ;
$message = '<strong>Resetarea parolei a fost ceruta pentru acest
cont.</strong><br>' ;
$message .= '<strong>Accesati urmatorul link:</strong> ' . $link;
$footer = '<strong>Forum A.C.E.</strong><br>' ;
$footer .= '<strong>' . date('d M Y') . '</strong>' ;

$this->load->helper('email');
$body = get_email_temp late('', $message , $footer, 'Resetare
parola');

return send_email ($from, $to_email , $subject , $body);
}
public function forgot()
{
$this->form_validation ->set_rules ('email', 'Email',
'required|valid_email' );

if ($this->form_validation ->run() == FALSE) {
$this->load->view('forgot' );
} else {
$email = $this->input->post('email');
$clean = $this->security ->xss_clean ($email);
$userInfo = $this->user_model ->getUserInfoByEma il($clean,
$this->usersTable );

if (!$userInfo ) {
$this->session->set_flashdata ('flash_message' , 'We can not
find your email address' );
redirect (site_url () . 'login');
}

if ($userInfo ->status != $this->status[2]) { //if status is not
completed
$this->session->set_flashdata ('flash_message' , 'Your
account is not in approved status' );
redirect (site_url () . 'login');
}

//build token

32
$token = $this->user_model ->insertToken ($userInfo ->id, $this-
>usersTable );
$qstring = $this->base64url_encode ($token);
$url = site_url () . 'reset_password/token/' . $qstring ;
$link = '<a href="' . $url . '">link< /a>';

if ($this->send_forgot_pass_email ($clean, $link)) {
$this->session->set_flashdata ('flash_message' , 'Ati primit
un email prin care va puteti reseta parola.' );
} else {
$this->session->set_flashd ata('flash_message' , 'Va rugam sa
reincercati!' );
}
redirect (site_url () . 'login');
exit;
}
}
This will redirect users to the forgot password form which has the php code in the
reset_password.php file:
<div class="col-lg-4 col-lg-offset-4">
<h2>Resetarea parolei </h2>
<h5>Buna <span><?php echo $firstName ; ?></span>,
<br>Te rugam sa introduci noua parola </h5>
<?php
$fattr = array('class' => 'form-signin');
echo
form_open (site_url ().'reset_password/token/' .$token, $fattr); ?>
<div class="form-group">
<?php echo form_password (
array(
'name'=>'password' ,
'id'=> 'password' ,
'placeholder' =>'Parola' ,
'class'=>'form-control' ,
'value' => set_value ('password' )
)); ?>
<?php echo form_error ('password' ) ?>
</div>
<div class="form-group">
<?php echo form_password (
array(
'name'=>'passconf' ,
'id'=> 'passconf' ,
'placeholder' =>'Confirmare Parola' ,
'class'=>'form-control',
'value'=> set_value ('passconf' )
)); ?>
<?php echo form_error ('passconf' ) ?>
</div>
<?php echo form_submit (array('value'=>'Reset!',
'class'=>'btn btn -lg btn-primary btn -block')); ?>
<?php echo form_close (); ?>
</div>

33
After the user inputs the new password and confirms it, the validation occurs in the
Front_main.php file:
public function reset_password($token = false)
{
$token = $this->base64url_decode ($token);
$cleanToken = $this->security ->xss_clean ($token);

$userInfo = $this->user_model ->isTokenValid ($cleanToken , $this-
>usersTable ); //either false or array();

if (!$userInfo ) {
$this->session->set_flashdata ('flash_message' , 'Token is
invalid or expired' );
redirect (site_url () . 'login');
}
$data = array(
'firstName' => $userInfo ->first_name ,
'email' => $userInfo ->email,
'token' => $this->base64url_encode ($token)
);

$this->form_validation ->set_rules ('password' , 'Password' ,
'required|min_length[5]' );
$this->form_validation ->set_rules ('passconf' , 'Password
Confirmation', 'required|matches[password]' );

if ($this->form_validation ->run() == FALSE) {
$this->load->view('reset_password' , $data);
} else {
$this->load->library('password' );
$post = $this->input->post(NULL, TRUE);
$cleanPost = $this->security ->xss_clean ($post);
$hashed = $this->password ->create_hash ($cleanPost ['password' ]);
$cleanPost ['password' ] = $hashed;
$cleanPost ['user_id' ] = $userInfo ->id;
unset($cleanPost ['passconf' ]);
if (!$this->user_model ->updatePassword ($cleanPost , $this-
>usersTable )) {
$this->session->set_flashdata ('flash_message' , 'There was a
problem updating your password' );
} else {
$this->session->set_flashdata ('flash_message' , 'Your
password has been updated. You may now login' );
}
redirect (site_url () . 'login');
}
}

34
3.2.3 Log out
The log out button is included in the menu so it will be present o n every page and the php code
is in the menu.php:
<li><a href="<?php echo base_url () . 'logout' ; ?>"><span><i class="fa
fa-sign-out"></i> Log out</span></a></li>
And the code behind the logout function is:
public function logout()
{
$this->session->sess_destroy ();
redirect (site_url () . 'login');
}

public function forgot()
{
$this->form_validation ->set_rules ('email', 'Email',
'required|valid_email' );

if ($this->form_validation ->run() == FALSE) {
$this->load->view('forgot' );
} else {
$email = $this->input->post('email');
$clean = $this->security ->xss_clean ($email);
$userInfo = $this->user_model ->getUserInfoByEmail ($clean,
$this->usersTable );

if (!$userInfo ) {
$this->session->set_flashdata ('flash_message' , 'We can not
find your email address' );
redirect (site_url () . 'login');
}

if ($userInfo ->status != $this->status[2]) { //if status is no t
completed
$this->session->set_flashdata ('flash_message' , 'Your
account is not in approved status' );
redirect (site_url () . 'login');
}

//build token
$token = $this->user_model ->insertTok en($userInfo ->id, $this-
>usersTable );
$qstring = $this->base64url_encode ($token);
$url = site_url () . 'reset_password/token/' . $qstring ;
$link = '<a href="' . $url . '">link</a>' ;

if ($this->send_forgot_pas s_email($clean, $link)) {
$this->session->set_flashdata ('flash_message' , 'Ati primit
un email prin care va puteti reseta parola.' );
} else {
$this->session->set_flashdata ('flash_message' , 'Va rugam sa
reincercati !');
}

35
redirect (site_url () . 'login');
exit;
}
}
And thus, the user will be logged out and sent to the login screen.

3.3 The main page
The main page also known as “Noutati” page is the page that users get redir ected after login
and the first thing they see is the latest article with the following code in the index.php file:
<div class="entry-post entry -post-fullwidth" >
<figure class="media">
<a href="<?php echo base_url () .
'articol/' . $latest_article ['id']; ?>">
<img src="<?php echo
assets_uploads_files_url () . strtolower (str_replace (' ', '',
$latest_article ['name_company' ])) . '/' . $latest_a rticle['poster' ]; ?>"
class="img-responsive img –
centered" alt="Image Thumbnail" />
</a>
</figure>
<div class="entry-content" >
<div class="entry-header">
<h2 class="entry-title">
<a href="<?php echo
base_url () . 'articol /' . $latest_article ['id']; ?>"><?php echo
$latest_article ['title']; ?></a>
</h2>
<div class="meta-line">
<span class="post-date"><i
class="fa fa-calendar" ></i><?php echo $latest_article ['creation_date_en' ];
?></span>
<span class="post-
comment" ><i class="fa fa-comments" ></i> <a href="<?php echo base_url () .
'articol/' . $latest_article ['id']; ?>">0 Comentarii </a></span>
</div>
</div>
<div class="excerpt" >
<p>Adaugat de: <strong> <?php
echo $latest_article ['name_company' ]; ?></strong></p>
<p class="read-more">
<a href="<?php echo
base_url () . 'articol/' . $latest_article ['id']; ?>" class="read-more">Vezi
Postare! </a>
</p>
</div>
</div>
Below the latest article other articles are shown, sorted by date and small er in section size than
the latest article:

36
<div class="clearfix margin -top-30 margin -bottom-30"></div>
<div class="row">
<?php if (!empty($articles )): ?>
<?php foreach ($articles as
$article ): ?>
<div class="col-sm-6">
<div class="post-entry-
card">
<a href="<?php echo
base_url () . 'articol/' . $article ['id']; ?>">
<img src="<?php
echo assets_uploads_files_url () . strtolower (str_replace (' ', '',
$article ['name_company' ])) . '/' . $article ['poster' ]; ?>"
class="img-
responsive img -centered height -280" alt="Post Thumbnail" >
</a>
<div class="post-info">
<h3 class="post-title">
<a href="<?php echo
base_url () . 'articol/' . $article ['id']; ?>"><?php echo $article ['title'];
?></a>
</h3>
<p class="post-
excerpt" >Adaugat de: <strong> <?php echo $article ['name_company' ];
?></strong></p>
<span class="post-meta">
<i class="fa fa-calendar –
o"></i> <?php echo $latest_article ['creation_date_en' ]; ?>
</span>
<a href="<?php echo
base_url() . 'articol/' . $article ['id']; ?>" class="read-more pull –
right">Vezi Postare! </a>
</div>
</div>
</div>
<?php endforeach ; ?>
<?php endif; ?>
</div>
And below the older articles section there is the popular section which displays four articles
which cur rently have the most views:
<section class="categorized -posts">
<h2 class="section -heading pull –
left">POPULAR</h2>
<a href="#" class="see-all-posts pull –
right">See all posts in Popular <i class="fa fa-long-arrow-right"></i></a>
<div class="clearfix" ></div>
<div class="row">
<div class="col-sm-6 col-lg-3">
<div class="post-entry post -entry-
simple">
<a href="#"><img
src="assets/img/blog/blog -med-img6.jpg" class="img-responsive" alt="Post
Thumbnail" ></a>
<h3 class="post-title"><a
href="#"> Jobs>> Php Developer </a></h3>
</div>

37
</div>
<div class="col-sm-6 col-lg-3">
<div class="post-entry post -entry-
simple">
<a href="#"><img
src="assets/img/blog/blog -med-img5.jpg" class="img-responsive" alt="Post
Thumbnail" ></a>
<h3 class="post-title"><a
href="#"> Code Golf: Editia a VI -a </a></h3>
</div>
</div>
<div class="col-sm-6 col-lg-3">
<div class="post-entry post -entry-
simple">
<a href="#"><img
src="assets/img/blog/blog -med-img4.jpg" class="img-responsive" alt="Post
Thumbnail" ></a>
<h3 class="post-title"><a
href="#">Summer Internship 2018 </a></h3>
</div>
</div>
<div class="col-sm-6 col-lg-3">
<div class="post-entry post -entry-
simple">
<a href="#"><img
src="assets/img/blog/blog -med-img3.jpg" class="img-responsive" alt="Post
Thumbnail" ></a>
<h3 class="post-title"><a
href="#">Jobs4IT: Tâ rgul de carieră @A.C.E</a></h3>
</div>
</div>
</div>
</section>
The code to get the latest article from the database is :
public function index()
{
// retrieve all articles
$articles = $this->article_model ->read_articles (true);
// store the newest article
$latest_article = $articles [0];
// and remove it from the older ones
unset($articles [0]);

$recommendations = $this->company_model –
>get_recommended_articles ();
$categories = $this->company_model ->get_categories_articles ();
$tags = $this->company_model ->get_tags_articles ();

/*front page*/
$this->load->view('index', array(
'latest_article' => $latest_article ,
'articles' => $articles ,
'recommendations' => $recommendations ,
'categories' => $categories ,
'tags' => $tags)
);

38
}

public function get_article ($id = false)
{
if ($id) {
$article = $this->article_model ->get_article_by_id ($id);
$this->load->view('article' , array('article' => $article ));
} else {
redirect(base_url () . 'home');
}
}

3.3.1 The recommended section
The recommended section is placed on t he right side of the main page and the code to generate
recommended articles is the following:
public function get_recommended_articles ()
{
$observed_articles = $tracked_categories = $tracked_tags =
$articles = array();
$type_user = !empty($this->session->userdata ['front_faculty' ]) ?
'0' : '1';

// get articles on which the current logged in user has commented
$this->db->select('*');
$this->db->where(array('id_user' => $this->session-
>userdata ['front_id' ], 'type_user' => $type_user ));
$query = $this->db->get($this::ARTICLE_COMMENT_TABLE );
$results = $query->result();

if (!empty($results )) {
foreach ($results as $result) {
array_push ($observed_articles , $result->id_article );
}
}

// get articles on which the current user has reviewed the
addressed comments
$this->db->select('*')
->from($this::ARTICLE_COMMENT_THUMB_TABLE )
->join($this::ARTICLE_COMMENT_TABLE ,
$this::ARTICLE_COMMENT_THUMB_TABLE . ".id_comment = " .
$this::ARTICLE_COMMENT_TABLE . ".id_article_comment" )
->where(array(
$this::ARTICLE_COMMENT_THUMB_TABLE . ".id_user" =>
$this->session->userdata ['front_id' ],
$this::ARTICLE_COMMENT_THUMB_TABLE . ".type_user" =>
$type_user )
);
$query = $this->db->get();
$results = $query->result();

if (!empty($results )) {
foreach ($results as $result) {
array_push ($observed_articles , $result->id_article );

39
}
}

if (!empty(array_unique ($observed_articles ))) {
// get all categories of the above observed articles
$this->db->select('*');
$this->db->where_in ('id_article' , array(implode(',',
array_unique ($observed_articles ))));
$query = $this->db->get($this::ARTICLE_CAT EGORY_TABLE );
$results = $query->result();

if (!empty($results )) {
foreach ($results as $result) {
array_push ($tracked_categories , $result->id_category );
}
}

// get all tags of the above observed articles
$this->db->select('*');
$this->db->where_in ('id_article' , array(implode(',',
array_unique ($observed_articles ))));
$query = $this->db->get($this::ARTICLE_TAG_TABLE );
$results = $query->result();

if (!empty($results )) {
foreach ($results as $result) {
array_push ($tracked_tags , $result->id_tag);
}
}
}

if (!empty(array_un ique($tracked_categories ))) {
// get all articles based on the above tracked categories and
tags
$this->db->select('*')
->from($this::ARTICLE_CATEGORY_TABLE )
->join($this::ARTICLE_TABLE , $this::ARTICLE_CATEGORY_TABLE
. ".id_article = " .$this::ARTICLE_TABLE. ".id_article" )
->where_in ($this::ARTICLE_CATEGORY_TABLE . ".id_category" ,
array(implode(',', array_unique ($tracked_categories ))));
$this->db->order_by ($this::ARTICLE_TABLE . ".creation_date" ,
'desc');
$query = $this->db->get();
$results = $query->result();

if (!empty($results )) {
foreach ($results as $result) {
$articles [$result->id_article ] = array(
'id' => $result->id_article ,
'creation_date' => date('d.m.Y', strtotime ($result-
>creation_date )),
'poster' => $result->poster,
'title' => $result->title
);
}
}
}

if (!empty(array_unique ($tracked_tags ))) {

40
// get all articles based on the above tracked categories and
tags
$this->db->select('*')
->from($this::ARTICLE_TAG_TABLE )
->join($this::ARTICLE_TABLE , $this::ARTICLE_TAG_TABLE .
".id_article = " .$this::ARTICLE_TABLE. ".id_article" )
->where_in ($this::ARTICLE_TAG_TABLE . ".id_tag" ,
array(implode(',', array_unique ($tracked_tags ))));
$this->db->order_by ($this::ARTICLE_TABLE . ".creation_date" ,
'desc');
$query = $this->db->get();
$results = $query->result();

if (!empty($results )) {
foreach ($results as $result) {
$articles [$result->id_article ] = array(
'id' => $result->id_article ,
'creation_date' => date('d.m.Y', strtotime ($result-
>creation_date )),
'poster' => $result->poster,
'title' => $result->title,
'company_name' => $this->get_company_by_id ($result-
>id_company )['name']
);
}
}
}

return $articles ;
3.3.2 The categories section
The categories section is placed on the right side of the main page under the recommended
section and has the following code:
The categories are stored in the categories table:
public function get_categories_articles ()
{
$this->db->select('*')
->from($this::ARTICLE_CATEGORY_TABLE )
->join($this::CATEGORY_TABLE , $this::ARTICLE_CATEGORY_TABLE .
".id_category = " . $this::CATEGORY_TABLE . ".id_category" );
$query = $this->db->get();
$results = $query->result();

if (!empty($results )) {
foreach ($results as $result) {
if (!empty($data[$result->id_category ])) {
$number_of_articles = $data[$result-
>id_category ]['articles_number' ] + 1;
$data[$result->id_category ]['articles_number' ] =
$number_of_articles ;
} else {
$data[$result->id_category ] = array(
'id_category' => $result->id_category ,
'name' => $result->name,

41
'articles_number' => 1
);
}
}
return $data;
}
return array();
}

Column name Description
id_category Unique identifier for each category created
name Appropriate name for each category created
Table 2. Categories table

3.3.3 The tags section
The categories section is placed on the right side of the main page under the category section
and has the following code in the index.php file:
public function get_tags_articles ()
{
$this->db->select('*')
->from($this::ARTICLE_TAG_TABLE )
->join($this::TAG_TABLE , $this::ARTICLE_TAG_TABLE . ".id_tag =
" . $this::TAG_TABLE . ".id_tag" );
$query = $this->db->get();
$results = $query->result();

if (!empty($results )) {
foreach ($results as $result) {
$data[$result->id_tag] = array(
'id_tag' => $result->id_tag,
'name' => $result->name
);
}
return $data;
}
return array();
}

42
This is the tags table:

Column name Description
id_tag Unique identifier for each tag created
name Appropriate name for each tag created
Table 3. Tag table

3.4 Article page
The individual article page contains the article title, author name, add date and the article body, the
code is the following:
<div class="col-md-9">
<article class="entry-post entry -post-single">
<header class="entry-header">
<h1 class="entry-title"><?php echo
$article ['title']; ?></h1>
<div class="meta-line">
<span class="post-author"><i class="fa fa-
user"></i> <a href="#"><?php echo $article ['name_company' ]; ?></a></span>
<span class="post-date"><i class="fa fa-
calendar" ></i> <?php echo $article ['creation_date_en' ]; ?></span>
<span class="post-comment"><i class="fa fa-
comments" ></i> <a href="#">4 Comments </a></span>
</div>
</header>
<figure class="media">
<a href="#">
<img src="<?php echo assets_uploads_files_url () .
strtolower (str_replace (' ', '', $article ['name_company' ])) . '/' .
$article ['poster' ]; ?>"
class="img-responsive img -centered" alt="by <?php
echo $article ['name_company' ]; ?>">
</a>
</figure>
<div class="content" >
<?php echo $article ['body']; ?>
</div>
</article>
<?php if (!empty($article ['tags'])): ?>

43
<div class="row">
<div class="col-md-12">
<h4>Tag-uri:</h4>
<?php $tags = explode(', ', $article ['all_tags' ]);
?>
<ul class="list-inline tag -list">
<?php foreach ($tags as $tag): ?>
<li><a href="#"><?php echo $tag;
?></a></li>
<?php endforeach ; ?>
</ul>
</div>
</div>
<?php endif; ?>
<section class="post-author-info">
<h3 class="section -heading sr -only">About
The Author </h3>
<div class="media">
<a href="#" class="media-left">
<img src="<?php echo
assets_uploads_url () . $article ['logo_company' ]; ?>" class="img-circle w -h-
60px" alt="Avatar" >
</a>
<div class="media-body">
<a href="#" class="author-
name"><?php echo $article ['name_company' ]; ?></a>
<p class="author-title"><?php echo
$article ['city_company' ]; ?></p>
</div>
</div>

The table from the database that stores all articles is called article:

44
A short description for each column in the article table :
Column name Description
id_article Unique identifier to each article and the primary
key of the article ta ble

id_company Unique identifier for each company

creation_date The date when the article was created

body The content of the article (text, images, videos)

title The title of the article

poster Obligatory banner that will be displayed on other
pages to recognize this article

type Boolean value to determine the type of comments

Table 4. Article table
At the end of each article we have the comment section whe re any type of user can:
Add a comment:
public function add_comment($post_data )
{
$id_article = $post_data ['id_article' ];
$comment = nl2br($post_data ['comment' ]);
$is_response = $post_data ['is_response' ];
$type_user = !empty($this->session->userdata ['front_faculty' ]) ?
'0' : '1';
$creation_date = date('Y-m-d H:i:s' );
$avatar = !empty($this->session->userdata ['front_faculty' ]) ?
$this->session->userdata ['front_avatar' ] : $this->session-
>userdata ['front_logo' ];
$user_name = !empty($this->session->userdata['front_faculty' ]) ?
$this->session->userdata ['front_last_name' ] . ' ' . $this-
>session->userdata ['front_first_name' ] : $this->session-
>userdata ['front_name' ];

$data_to_insert = array(
'id_article' => $id_article ,
'id_user' => $this->session->userdata ['front_id' ],
'type_user' => $type_user , // 0 = student, 1 = company

45
'creation_date' => $creation_date ,
'body' => $comment ,
'response_to' => $is_response
);
$this->db->insert($this::TABLE_ARTICLE_COMMENT , $data_to_insert );

return json_encode (
array(
'id_comment' => $this->db->insert_id (),
'avatar' => assets_uploads_url () . $avatar,
'creation_date' => date('d.m.Y H:i' ,
strtotime ($creation_date )),
'user_name' => $user_name ,
'comment' => $comment
)
);
}
Edit previously added comments:
public function edit_comment ($post_data )
{
$id_comment = $post_data ['id_comment' ];
$updated_comment = nl2br($post_data ['updated_comment' ]);

$this->db->where('id_article_comment' , $id_comment );
$this->db->update($this::TABLE_ARTICLE_COMMENT , array('body' =>
$updated_ comment));

return json_encode (
array(
'comment' => $updated_comment
)
);
}
Delete previously added comments:
public function delete_comment ($id)
{
$this->db->where('id_article_comment ', $id);
$this->db->delete($this::TABLE_ARTICLE_COMMENT );
}
Review comments (give them thumbs up or down)
public function review_comment ($post_data )
{
$type_user = !empty($this->session->userdata ['front_faculty' ]) ?
'0' : '1';
$user_of_comment = $this-
>get_user_of_comment ($post_data ['id_comment' ]);
// if the user that reviews is the one who made the comment

if (($user_of_comment ['id'] == $this->session-
>userdata ['front_id' ])

46
&& ($type_user == $user_of_comment ['type'])) {
// return empty response
return false;
}

$data_to_insert = array(
'id_comment' => $post_data ['id_comment' ],
'type' => $post_data ['review' ],
'id_user' => $this->session->userdata ['front_id' ],
'type_user' => $type_user // 0 = student, 1 = company
);

$this->db->insert($this::TABLE_ARTICLE_COMMENT_THUMB ,
$data_to_insert );

return json_encode (
array(
'id_review_comment' => $this->db->insert_id ()
)
);
}
Or cancel a comment review previously made:
public function delete_review_comment ($id)
{
$this->db->where('id_article_comment_thumb' , $id);
$this->db->delete($this::TABLE_ARTICLE_COMMENT_THUMB );
}
Comments mapping on the page (with Js)
var articleCommentsContainer = $('article.comments' );

// display add comment textarea
$('.add-comment-header').click(function (){
$('#add_comment_form' ).toggle('slow');
});

/**
* Adding a typical comment
*/
$('#add_comment_form' ).submit(function (event){
event.preventDefault ();
var form = $(this),
textarea = form.find('textarea' ),
message = textarea.val(),
id_article = textarea .attr('data-id');

$.post('../adaugare -comentariu' , {'id_article' : id_article ,
'comment' : message, 'is_response' : 0}, function (response ){
textarea .val('');
form.toggle('slow');
response = JSON.parse(response );
// add the new comment as the first one in the list
var commentsContainer = $('article.comments ul.media –
list').first();

47
commentsContainer .prepend('<li class="media">' +
$('#typica l_comment' ).html() + '</li>');

// build the new comment's container
var inserted_comment = commentsContainer .find('li').first();
// map the new inserted comment into DOM
map_inserted_comment (inserted_comment , response );
});
});
function map_inserted_comment (inserted_comment , response )
{
inserted_comment .attr('id', 'row_comment_' + response .id_comment );
inserted_comment .find('div').first().attr('id',
'comment_displayed_' + response.id_comment );
// adding avatar
inserted_comment .find('#comment_displayed_' + response .id_comment +
' img.avatar' ).attr('src', response .avatar);
// adding name
inserted_comment .find('.media-body .comment -author
a').text(response.user_name );
// adding comment date
inserted_comment .find('.media-body
span.timestamp' ).text(response .creation_date );
// adding comment body
inserted_comment .find('.media-body p.comment –
body').html(response .comment);

// make edit/delete buttons functional
inserted_comment .find('span.edit -comment' ).attr('data-id',
response .id_comment );
inserted_comment .find('span.delete -comment' ).attr('data-id',
response .id_comment );
inserted_comment .children('div').eq(1).attr('id', 'comment_edited_'
+ response .id_comment );
inserted_comment .find('#comment_edited_' + response .id_comment + '
textarea' ).val(response .comment);
inserted_comment .find('.update -comment' ).attr('data-id',
response .id_comment );
inserted_comment .find('.cancel -editing' ).attr('data-id',
response .id_comment );
}
/**
* Adding a response comment
*/
// first, display the textarea in which the comment will be written
articleCommentsContainer .on('click', '.answer -to-comment' , function (){
var commentId = $(this).attr('data-id');
// display new comment textarea
$('#respond_to_' + commentId ).removeClass ('hidden' );
});
// secondly, send to server the new updated message
articleCommentsContainer .on('click', '.add-response -comment' ,
function (){
var commentId = $(this).attr('data-id'),
textarea = $('#respond_to_' + commentId + ' textarea' ),
message = textarea .val(),

48
id_article = textarea .attr('data-id'),
commentLevel = $(this).attr('data-comment-level');

$.post('../adaugare -comentariu' , {'id_article' : id_article ,
'comment' : message, 'is_response' : commentId }, function (response ){
textarea .val('');
$('#respond_to_' + commentId ).addClass ('hidden' );
response = JSON.parse(response );
var mainContainer = $('#comment_displayed_' + commentId );

// if another response has been already added, just add another
element to the list
if (mainContainer .find('ul.media -list').length) {
mainContainer .find('.media-body ul.media -list').append('<li
class="media comment -by-author">' + $('#typical_comment' ).html() +
'</li>');
} else {
// otherwise, create the list
mainContainer .find('.media-body').append('<ul class="media –
list">'
+ '<li class="media comment -by-author">' +
$('#typical_comment' ).html() + '</li>' + '</ul>');
}
// map the inserted comment into DOM
var inserted_comment = mainContainer .find('.media-body
ul.media -list li' ).first();
map_inserted_comment (inserted_comment , response );
});
});
// or cancel the edit proces s
articleCommentsContainer .on('click', '.cancel -adding-response' ,
function (){
var commentId = $(this).attr('data-id');
// hide new comment textarea
$('#respond_to_' + commentId ).addClass ('hidden' );
});

/**
* Edit a comment
*/
// first, display the form with the current comment
articleCommentsContainer .on('click', '.edit-comment' , function (){
var commentId = $(this).attr('data-id');
$('#comment_edited_' + commentId ).removeClass ('hidden' );
$('#comment_displayed_' + commentId ).addClass ('hidden' );
});
// secondly, send to server the new updated message
articleCommentsContainer .on('click', '.update -comment' , function (){
var commentId = $(this).attr('data-id'),
updatedComment = $('#comment_edited_' +
commentId ).find('textarea' ).val();

$.post('../editare -comentariu' , {'id_comment' : commentId ,
'updated_comment' : updatedComment }, function (response ){
response = JSON.parse(response );

$('#row_comment_' + commentId ).find('.media-body p.comment –
body').html(response .comment);
$('#comment_edited_' + commentId ).addClass ('hidden' );

49
$('#comment_displayed_' + commentId ).removeClass ('hidden' );
});
});
// or cancel the edit process
articleCommentsContainer .on('click', '.cancel -editing' , function (){
var commentId = $(this).attr('data-id');
$('#comment_edited_' + commentId ).addClass ('hidden' );
$('#comment_displayed_' + commentId).removeClass ('hidden' );
});

/**
* Delete a comment
*/
articleCommentsContainer .on('click', '.delete -comment' , function (){
var commentId = $(this).attr('data-id');

$.post('../stergere -comentariu' , {'id_comment' : commentId },
function (){
$("#row_comment_" + commentId ).fadeOut("slow", function () {
// remove element
$(this).remove();
});
})
});

/**
* Adding a like / thumbs up
*/
articleCommentsContainer .on('click', '.like-comment' , function () {
var commentId = $(this).attr('data-id'),
likeContainer = $(this),
commentContainer = $('#row_comment_' + commentId ),
commentParentList = commentConta iner.parent('ul.media -list'),
reviewId = likeContainer .attr('data-review-id');

if (reviewId != null) {
// if current user wants to withdraw its thumbs up
$.post('../stergere -review-comentariu' , {'id_review' :
reviewId}, function (){
likeContainer .removeAttr ('data-review-id');
likeContainer .find('i').removeClass ('fa-thumbs-
up').addClass ('fa-thumbs-o-up');

likeContainer .find('span').text(parseInt (likeContainer .find('span').text(),
10) – 1);

if (commentParentList .length > 1) {
var nextComment = commentContainer .next();
if (nextComment .length) {
nextComment .after(commentContainer .detach());
}
}
});
} else {
// adding thumbs up
$.post('../adaugare -review-comentariu' , {'id_comment' :
commentId , 'review' : '1'}, function (response ){
if (!response .length) {
alert('You can NOT review your own comment!' );

50
return false;
}
response = JSON.parse(response );

likeContainer .attr('data-review-id',
response .id_review_comment );
likeContainer .find('i').removeClass ('fa-thumbs-o-
up').addClass ('fa-thumbs-up');
likeContainer .find('span').text(1 +
parseInt (likeContainer .find('span').text(), 10));
if (commentParentList .length > 1) {
var previousComment = commentContainer .prev();
if (previousComment .length) {
previousComment .before(commentContainer .detach());
}
}
// if comment was previously down -voted (and not by current
user), remove thumbs down
var dislikeContainer = likeContainer .next(),
dislikeReviewId = dislikeContainer .attr('data-review-
id');

if (dislikeContainer .find('i').hasClass ('fa-thumbs-down')
&& (dislikeReviewId != null)) {
$.post('../stergere -review-comentariu' , {'id_review' :
dislikeContainer .attr('data-review-id')}, function (){
dislikeContainer .removeAttr ('data-review-id');
dislikeContainer .find('i').removeClass ('fa-thumbs-
down').addClass ('fa-thumbs-o-down');

dislikeContainer .find('span').text(parseInt (dislikeContainer .find('span').t
ext(), 10) – 1);
});
}
})
}
});

/**
* Adding a dislike / thumbs down
*/
articleCommentsContainer .on('click', '.dislike -comment' , function () {
var commentId = $(this).attr('data-id'),
dislikeContainer = $(this),
commentContainer = $('#row_comment_' + commentId ),
commentParentList = commentContainer .parent('ul.media -list'),
reviewId = dislikeContainer .attr('data-review-id');

if (reviewId != null) {
// if current user wants to withdraw its thumbs down
$.post('../stergere -review-comentariu' , {'id_review' :
reviewId }, function (){
dislikeContainer .removeAttr ('data-review-id');
dislikeContainer .find('i').removeCl ass('fa-thumbs-
down').addClass ('fa-thumbs-o-down');

dislikeContainer .find('span').text(parseInt (dislikeContainer .find('span').t
ext(), 10) – 1);

51
if (commentParentList .length > 1) {
var previousComment = commentContainer .prev();
if (previousComment .length) {
previousComment .before(commentContainer .detach());
}
}
});
} else {
// adding thumbs down
$.post('../adaugare -review-comentariu' , {'id_comment' :
commentId , 'review' : '0'}, function (response ){
if (!response .length) {
alert('You can NOT review your own comment!' );
return false;
}
response = JSON.parse(response );

dislikeContainer .attr('data-review-id',
response .id_review_comment );
dislikeContainer .find('i').removeClass ('fa-thumbs-o-
down').addClass ('fa-thumbs-down');
dislikeContainer .find('span').text(1 +
parseInt (dislikeContainer .find('span').text(), 10));
if (commentParentList .length > 1) {
var nextComment = commentContainer .next();
if (nextCommen t.length) {
nextComment .after(commentContainer .detach());
}
}

});
}
})
}
});

The comments are stored in the article_co mment table:

Figure 33. Article comments table

52
Column name Description
id_article_comment Unique identifier for the article and also the
primary key of this table
id_article The id of the article that is commente upon
id_use r The id of the users that post comments
type_user The type of the users that post comments
(students or companies)
creation_date The creation date of each comment
body The body of the comment (text)
response_to If the comment is a response to another comment,
the id of that parent comment.
Table 5. Article comments table

3.5 Companies page
The companies page brings a list of partenered companies which can post articles and
comments on the app. The code to fetch the company list is :
public function get_companies ()
{
$this->db->select('*');
$query = $this->db->get($this::ARTICLE_TABLE );
$results = $query->result();

if (!empty($results )) {
foreach ($results as $result) {
$company = $this->get_company_by_id ($result->id_company );
if ($company ['status' ] == $this::STATUS_COMPLETED ) {
$data[$result->id_company ] = array(
'id_company' => $result->id_company ,
'name' => $company ['name'],
'city' => $company ['city'],
'logo' => $company ['logo'],
'description' => $company ['description' ],
'address' => $company ['address' ]
);
}
}
return $data;

53
}
return array();
}
Furthermore, when clicking a company from this page, the user will be redirected to a new page
where only the articles crea ted by that company are selected and displayed in ordered by date. The
code to get all the articles from a single company is:
public function get_articles_by_company ($id_company )
{
$this->db->select('*');
$this->db->where(array('id_comp any' => $id_company ));
$this->db->order_by ('creation_date' , 'desc');
$query = $this->db->get($this::ARTICLE_TABLE );
$results = $query->result();

if (!empty($results )) {
foreach ($results as $result) {
$company = $this->get_company_by_id ($id_company );
$data[$result->id_article ] = array(
'title' => $result->title,
'poster' => $result->poster,
'creation_date' => date('d.m.Y', strtotime ($result-
>creation_date )),
'creation_date_en' => date('M d, Y' , strtotime ($result-
>creation_date )),
'#comments' => $this->get_number_of_comments ($result-
>id_article ),
'id_company' => $result->id_company ,
'name' => $company ['name'],
'city' => $company ['city'],
'logo' => $company ['logo'],
'description' => $company ['description' ],
'address' => $company ['address' ]
);
}
return $data;
}
return array();
}
The companies are stored in the company table:

54

Figure 34. Company table

Column name Description
id Unique i dentifier for each company and the
primary key of the table
name The company’s name
city The city where the company is located
logo The current logo of the company
description A description of the company provided by the
company
email The email of the company
password The password of the company’s account
address The current address of the company
register_date The date when the company registered
last_login The time of the last login of the company
status Status of the company (completed registra tion or
not)
Table 6. Company tabl e

55
4 CONCLU SIONS
The main goal was to initiate a minimal interaction between students and companies and I firmly
believe that I achieved that . Students have the possibility to be noticed by companies and their
growth, passion and interest can result in getting hired. Virtually all three parts (student, faculty,
company) will ultimately benefit from such interaction.
Based on feedback on articles, companies could figure out how to better target student s to make
them even more curious and willing to continue in this area. Students would be more motivated to
receive this minimal attention in the application from companies. And, as an intermediary, the ACE
managed to create relationships and build a better image not only in Craiova but also in other major
cities of Romania.
Naturally there i s a lot of room for improvement . If the applicati on reaches its original target , this
does not mean it is the ideal application. Throughout its development, I have notic ed many aspects
that can be enhanced and many features that can be implemented to turn it into an application as
technically complex as it is useful in several respects.
It has started as a small forum but it can turn into much more than that. What is impo rtant is that
the first step has been achieved – we have the students in the same place together with IT companies.
As an improvement ideea, s ince most companies have internal programs for students (interships,
academies, trainings, etc.), the selection an d enrollment process could somehow be portrayed in this
application, as I repeat, we already have the same place and students and companies.
Another idea would be that the situation of college projects done by students could be somehow
made public for comp anies (of course, invisible to other students , and only with the student’s
approval ). This would be somewhat an extension of the idea above, ideal for situations where there
are a lot of students enrolled in an academy and companies do not have much data c ollected about
them and this could give the chance to the students to impress some companies in the field they wish
to start their careers.

56
5 BIBLIOGRA PHY
During the planning and development of this dissertation project the foll owing web resources were consulted:

 http://php.net/ – PHP
 https://codeigniter.com/ – CodeIgniter
 https://www.froal a.com/wysiwyg -editor – Froala Editor
 http://phpmailer.worxware.com/index.php?pg=tutorial – PHPMailer
 https://en.wikipedia.org/ wiki/MySQL – MySQL
 http://www.w3schools.com/html/default.asp – HTML
 http://www.w3schools.com/css/default.asp – CSS
 http://www.w3schools.com/js/default.asp – JavaScript
 https://jquery.com – jQuery
 http://www.w3schools.com/json/ default.asp – JSON
 http://getbootstrap.com/ – Bootstrap
 https://ro.wikipedia.org/wiki/Model -view -controller – MVC pattern
 http://www.w3schools.com/ajax/default.asp – AJAX
 https://www.apachefriends.org/index.html – XAMPP
 https://colorlib.com/polygon/elaadmin/index.html – The template of the back -end
administration panel
 https://wrapbootstrap.com/theme/bra vana -responsive -website -template -WB0D6B38R – The
template of the front -end interface
 https://mlocati.github.io/articles/php -windows -imagick.html – Details for adding the
custom library needed for the Froala editor

57
A. SOURCE CODE

 application/config/database.php (credentialele pentru baza de date)
$active_group = 'default' ;
$query_builder = TRUE;

$db['default' ] = array(
'dsn' => '',
'hostname' => 'localhost' ,
// 'dbport' => '3306',
'username' => 'root',
'password' => '',
'database' => 'forum_ace' ,
'dbdriver' => 'mysqli' ,
'dbprefix' => '',
'pconnect' => FALSE,
'db_debug' => (ENVIRONMENT !== 'production' ),
'cache_on' => FALSE,
'cachedi r' => '',
'char_set' => 'utf8',
'dbcollat' => 'utf8_general_ci' ,
'swap_pre' => '',
'encrypt' => FALSE,
'compress' => FALSE,
'stricton' => FALSE,
'failover' => array(),
'save_queries' => TRUE
);

 application/config/routes.php (rutel e aplicatiei)
$route['default_controller' ] = 'Front_article' ;
$route['404_override' ] = '';
$route['translate_uri_dashes' ] = FALSE;
$route['assets/(:any)' ] = 'assets/$1' ;

/* Admin Routes */
$route['admin'] = 'Admin_main/index' ; // main admin route
// Admin user main functions
$route['admin/login' ] = 'Admin_main/login' ;
$route['admin/register' ] = 'Admin_main/register' ;
$route['admin/forgot' ] = 'Admin_main/forgot' ;
$route['admin/reset_password/token/(:any)' ] =
'Admin_main/reset_password/$1' ;
$route['admin/complete/token/(:any)' ] = 'Admin_main/complete/$1' ;
$route['admin/approve -user'] = 'Admin_main/approve_request' ;
$route['admin/logout' ] = 'Admin_main/logout' ;
$route['admin/profilul -meu'] = 'Admin_main/get_user_profile' ;
// Companies routes
$route['admin/companii' ] = 'Admin_company/read' ;
$route['admin/companii/(:any)' ] = 'Admin_company/read/$1' ;
$route['admin/adaugare -companie' ] = 'Admin_company/create' ;
$route['admin/editare -companie/(:any)' ] = 'Admin_company/update/$1' ;
$route['admin/st ergere-companie' ] = 'Admin_company/delete' ;
// Students routes

58
$route['admin/studenti' ] = 'Admin_student/read' ;
$route['admin/studenti/(:any)' ] = 'Admin_student/read/$1' ;
$route['admin/adaugare -student' ] = 'Admin_student/create' ;
$route['admin/editare -student/(:any)' ] = 'Admin_student/update/$1' ;
$route['admin/stergere -student' ] = 'Admin_student/delete' ;
$route['admin/studenti -activi'] = 'Admin_student/get_students_activity' ;
// Articles routes
$route['admin/articole' ] = 'Admin_article/read' ;
$route['admin/articole/(:any)' ] = 'Admin_article/read/$1' ;
$route['admin/adaugare -articol' ] = 'Admin_article/create' ;
$route['admin/editare -articol/(:any)' ] = 'Admin_article/update/$1' ;
$route['admin/stergere -articol' ] = 'Admin_article/delete' ;
$route['admin/top -articole'] = 'Admin_article/get_top_articles' ; // ?
$route['admin/upload -image'] = 'Admin_article/upload_image' ;
$route['admin/delete -image'] = 'Admin_article/delete_image' ;
$route['admin/upload -file'] = 'Admin_article/upload_file' ;
$route['admin/delete -file'] = 'Admin_article/delete_file' ;
$route['admin/categorii -articole' ] = 'Admin_article/read_categories' ;
$route['admin/adaugare -categorie' ] = 'Admin_article/create_category' ;
$route['admin/editare -categorie/(:any)' ] =
'Admin_article/update_category/$1' ;
$route['admin/stergere -categorie' ] = 'Admin_article/delete_category' ;
$route['admin/taguri -articole' ] = 'Admin_article/read_tags' ;
$route['admin/adaugare -tag'] = 'Admin_article/create_tag' ;
$route['admin/editare -tag/(:any)' ] = 'Admin_article/update_tag/$1' ;
$route['admin/stergere -tag'] = 'Admin_article/delete_tag' ;
// Admin search
$route['admin/cautare/(:any)' ] = 'Admin_search/read/$1' ;

/* Front Routes */
$route['acasa'] = 'Front_article/index' ;
$route['login'] = 'Front_main/login' ;
$route['register' ] = 'Front_m ain/register' ;
$route['forgot' ] = 'Front_main/forgot' ;
$route['reset_password/token/(:any)' ] = 'Front_main/reset_password/$1' ;
$route['complete/token/(:any)' ] = 'Front_main/complete/$1' ;
$route['logout' ] = 'Front_main/logout' ;
$route['my-profile' ] = 'Front_main/get_user_profile' ;
$route['articol/(:any)' ] = 'Front_article/get_article/$1' ;
$route['trending' ] = 'Front_article/get_trending_articles' ;
$route['companii' ] = 'Front_company/get_companies' ;
$route['articole -companie/(:any)' ] =
'Front_article/get_arti cles_by_company/$1' ;
$route['studenti -activi'] = 'Front_student/get_active_students' ;
$route['adaugare -comentariu' ] = 'Front_article/add_comment' ;
$route['editare -comentariu' ] = 'Front_article/edit_comment' ;
$route['stergere -comentariu' ] = 'Front_article/d elete_comment' ;
$route['adaugare -review-comentariu' ] = 'Front_article/review_comment' ;
$route['stergere -review-comentariu' ] =
'Front_article/delete_review_comment' ;

 assets/js/my -custom -scripts.js (scripturile custom ale aplicatiei scrise in JavaScript)
/* Custom app scripts */

/**
* Initiate datatable
*/
$(function (){
$('#recent_companies, #recent_students, #all_companies,
#all_students, #all_categories, #all_tags' ).DataTable ();
});

59
/**
* Initiate custom select2
*/
$(function (){

$('#article_c ategories,#article_tags' ).select2({ closeOnSelect :false});
});

/***
* Get input file path and add it to the source of a image to preview it
* @param input
*/
function readURL(input) {
if (input.files && input. files[0]) {
var reader = new FileReader();

reader.onload = function (e) {
$('#img_preview' ).attr('src', e.target.result);
}

reader.readAsDataURL (input.files[0]);
}
}

$(document ).ready(function (){
/**
* On-click handler to dynamically app rove a user
*/
$('button.approve-user').click(function () {
var id = $(this).attr('id'),
email = $(this).attr('data-email'),
userTable = $(this).attr('data-table-name'),
button = $(this),
slashSign = button.closest('td').find('strong' );

$.post('admin/approve -user', {id: id, email: email, userTable :
userTable }).done(function (response) {
if (response == true) {
button.closest('td').find('span').removeClass ('badge-
warning' ).addClass ('badge-success' ).text('Approved' );
slashSign .remove();
button.remove();
}
});
});

/**
* On-click handler to dynamically delete data from db and also
remove it from DOM
*/
$('button.delete-company').click(function (){
var id = $(this).attr('id'),
logo = $(this).attr('data-logo');

$.post('stergere -companie' , {id: id, logo: logo}, function (){
$("#company -record-" + id).fadeOut("slow", function () {
// remove element
$(this).remove();
});
});
});

/**
* On-click handler to dynamically delete data from db and also
remove it from DOM
*/

60
$('button.delete-student').click(function (){
var id = $(this).attr('id'),
avatar = $(this).attr('data-avatar');

$.post('stergere -student' , {id: id, avatar: avatar}, function (){
$("#student -record-" + id).fadeOut("slow", function () {
// remove element
$(this).remove();
});
});
});

/**
* On-click handler to dynamically delete data from db and also
remove it from DOM
*/
$('button.delete-category ').click(function (){
var id = $(this).attr('id');

$.post('stergere -categorie' , {id: id}, function (){
$("#category -record-" + id).fadeOut("slow", function () {
// remove element
$(this).remove();
});
});
});

/**
* On-click handler to dynamically delete data from db and also
remove it from DOM
*/
$('button.delete-tag').click(function (){
var id = $(this).attr('id');

$.post('stergere -tag', {id: id}, function (){
$("#tag-record-" + id).fadeOut("slow", function () {
// remove element
$(this).remove();
});
});
});

/**
* Preview image (input file upload)
*/
$('#poster' ).change(function (){
// show image preview container
var previewNode = $('#img_preview' ).closest('div');
previewNode .attr('style','');
// build image preview src
readURL(this);
// if no file has been chosen, hide image contai ner
if (!(this.files && this.files[0])) {
previewNode .attr('style','display: none;' );
}
});

/**
* Send Froala content as html to server to be further stored into
db
*/
$('#add_article_form' ).find('#submit' ).click(function (){
var articleBody =
$(this).find('#article_body' ).froalaEditor ('html.get' );
$(this).find('#article_body' ).text(articleBody );
$('#add_article_form' ).submit();});

61

$('#edit_article_form' ).find('#submit' ).click(function(){
var articleBody =
$(this).find('#article_body' ).froalaEditor ('html.get' );
$(this).find('#article_body' ).text(articleBody );
$('#edit_article_form' ).submit();
});

/**–––––––
* Article Comments log ic
* ––––––– */
var articleCommentsContainer = $('article.comments ');

// display add comment textarea
$('.add-comment-header').click(function (){
$('#add_comment_form' ).toggle('slow');
});

/**
* Adding a typical comment
*/
$('#add_comment_form' ).submit(function (event){
event.preventDefault ();
var form = $(this),
textarea = form.find('textarea' ),
message = textarea .val(),
id_article = textarea .attr('data-id');

$.post('../adaugare -comentariu' , {'id_article' : id_article ,
'comment' : message, 'is_response' : 0}, function (response){
textarea .val('');
form.toggle('slow');
response = JSON.parse(response);
// add the new comment as the first one in the list
var commentsContainer = $('article.comments ul .media-
list').first();
commentsContainer .prepend('<li class="media">' +
$('#typical_comment' ).html() + '</li>');

// build the new comment's container
var inserted_comment = commentsContainer .find('li').first();
// map the new inserted comment into DOM
map_inserted_comment (inserted_comment , response);
});
});

/**
* Map newly inserted comment into DOM
* @param inserted_comment
* @param response
*/
function map_inserted_comment (inserted_comment, response)
{
inserted_comment. attr('id', 'row_comment_' +
response. id_comment );
inserted_comment. find('div').first().attr('id',
'comment_displayed_' + response. id_comment );
// adding avatar
inserted_comment. find('#comment_displayed_' +
response. id_comment + ' img.avatar' ).attr('src', response. avatar);
// adding na me
inserted_comment. find('.media-body .comment -author
a').text(response.user_name);
// adding comment date
inserted_comment. find('.media-body
span.timestamp' ).text(response.creation_date);

62
// adding comment body
inserted_comment. find('.media-body p.comment –
body').html(response. comment);

// make edit/delete buttons functional
inserted_comment. find('span.edit -comment' ).attr('data-id',
response. id_comment );
inserted_comment. find('span.delete -comment').attr('data-id',
response. id_comment );
inserted_comment. children ('div').eq(1).attr('id',
'comment_edited_' + response. id_comment );
inserted_comment. find('#comment_edited_' + response. id_comment +
' textarea' ).val(response. comment);
inserted_comment. find('.update -comment' ).attr('data-id',
response. id_comment );
inserted_comment. find('.cancel -editing' ).attr('data-id',
response. id_comment );
}

/**
* Adding a response comment
*/
// first, display the tex tarea in which the comment will be written
articleCommentsContainer .on('click', '.answer -to-comment' ,
function (){
var commentId = $(this).attr('data-id');
// display new comment textarea
$('#respond_to_' + commentId ).removeClass ('hidden' );
});
// secondly, send to server the new updated message
articleCommentsContainer .on('click', '.add-response -comment' ,
function (){
var commentId = $(this).attr('data-id'),
textarea = $('#respond_to_' + commentId + ' textarea' ),
message = textarea .val(),
id_article = textarea .attr('data-id'),
commentLevel = $(this).attr('data-comment-level');

$.post('../adaugare -comentariu' , {'id_article' : id_article ,
'comment' : message, 'is_response' : commentId }, function (response){
textarea .val('');
$('#respond_to_' + commentId ).addClass ('hidden' );
response = JSON.parse(response);
var mainContainer = $('#comment_displayed_' + commentId );

// if another response has been already added, just add
another element to the list
if (mainContainer .find('ul.media -list').length) {
mainContainer .find('.media-body ul.media –
list').append('<li class="media comment -by-author">' +
$('#typical_comment' ).html() + '</li>');
} else {
// otherwise, create the list
mainContainer .find('.media-body').append('<ul
class="media -list">'
+ '<li class="media comment -by-author">' +
$('#typical_comment' ).html() + '</li>' + '</ul>');
}
// map the inserted comment into DOM
var inserted_comment = mainContainer .find('.media-body
ul.media -list li' ).first();
map_inserted_comment (inserted_comment , response);
});
});
// or cancel the edit process
articleCommentsContainer .on('click', '.cancel -adding-response' ,

63
function (){
var commentId = $(this).attr('data-id');
// hide new comment textarea
$('#respond_to_' + commentId ).addClass ('hidden' );
});

/**
* Edit a comment
*/
// first, display the form with the current comment
articleCommentsContainer .on('click', '.edit-comment' , function (){
var commentId = $(this).attr('data-id');
$('#comment_edited_' + commentId ).removeClass ('hidden' );
$('#comment_displayed_' + commentId ).addClass ('hidden' );
});
// secondly, send to server the new updated message
articleCommentsContainer .on('click', '.update-comment' , function (){
var commentId = $(this).attr('data-id'),
updatedComment = $('#comment_edited_' +
commentId ).find('textarea' ).val();

$.post('../editare -comentariu' , {'id_comment' : commentId ,
'updated_comment' : updatedCom ment}, function (response){
response = JSON.parse(response);

$('#row_comment_' + commentId ).find('.media-body p.comment-
body').html(response. comment);
$('#comment_edited_' + commentId ).addClass ('hidden' );
$('#comment_displayed_' + commentId ).removeClass ('hidden' );
});
});
// or cancel the edit process
articleCommentsContainer .on('click', '.cancel -editing' , function (){
var commentId = $(this).attr('data-id');
$('#comment_edit ed_' + commentId ).addClass ('hidden' );
$('#comment_displayed_' + commentId ).removeClass ('hidden' );
});

/**
* Delete a comment
*/
articleCommentsContainer .on('click', '.delete -comment' , function (){
var commentId = $(this).attr('data-id');

$.post('../stergere -comentariu' , {'id_comment' : commentId },
function (){
$("#row_comment_" + commentId ).fadeOut("slow", function () {
// remove element
$(this).remove();
});
})
});

/**
* Adding a like / thumbs up
*/
articleCommentsContainer .on('click', '.like-comment' , function () {
var commentId = $(this).attr('data-id'),
likeContainer = $(this),
commentContainer = $('#row_comment_' + commentId ),
commentParentList = commentContainer .parent('ul.media –
list'),
reviewId = likeContainer .attr('data-review-id');

if (reviewId != null) {
// if current user wants to withdraw its t humbs up

64
$.post('../stergere -review-comentariu' , {'id_review' :
reviewId }, function (){
likeContainer .removeAttr ('data-review-id');
likeContainer .find('i').removeClass ('fa-thumbs-
up').addClass ('fa-thumbs-o-up');

likeContainer .find('span').text(parseInt (likeContainer .find('span').text
(), 10) – 1);

if (commentParentList .length > 1) {
var nextComment = commentContainer .next();
if (nextComment .length) {
nextComment .after(commentContainer .detach());
}
}
});
} else {
// adding thumbs up
$.post('../adaugare -review-comentariu' , {'id_comment' :
commentI d, 'review' : '1'}, function (response){
if (!response. length) {
alert('You can NOT review your own comment!' );
return false ;
}
response = JSON.parse(response);

likeContainer .attr('data-review-id',
response.id_review_comment);
likeContainer .find('i').removeClass ('fa-thumbs-o-
up').addClass ('fa-thumbs-up');
likeContainer .find('span').text(1 +
parseInt (likeContainer .find('span').text(), 10));
if (commentParentList .length > 1) {
var previousComment = commentContainer .prev();
if (previousComment .length) {

previousComment .before(commentContainer .detach());
}
}
// if comment was previously down -voted (and not by
current user), remove thumbs down
var dislikeContainer = likeContainer .next(),
dislikeReviewId = dislikeCont ainer.attr('data-
review-id');

if (dislikeContainer .find('i').hasClass ('fa-thumbs-
down') && (dislikeReviewId != null)) {
$.post('../stergere -review-comentariu' ,
{'id_review' : dislikeContainer .attr('data-review-id')}, function(){
dislikeContainer .removeAttr ('data-review-id');
dislikeContainer .find('i').removeClass ('fa-
thumbs-down').addClass ('fa-thumbs-o-down');

dislikeContainer .find('span').text(parseInt(dislikeContainer .find('span'
).text(), 10) – 1);
});
}
})
}
});

/**
* Adding a dislike / thumbs down
*/
articleCommentsContainer .on('click', '.dislike -comment' , function (){
var commentId = $(this).attr('data-id'),

65
dislikeContainer = $(this),
commentContainer = $('#row_comment_' + commentId ),
commentParentList = commentContainer .parent('ul.media –
list'),
reviewId = dislikeCo ntainer.attr('data-review-id');

if (reviewId != null) {
// if current user wants to withdraw its thumbs down
$.post('../stergere -review-comentariu' , {'id_review' :
reviewId }, function (){
dislikeContainer .removeAttr('data-review-id');
dislikeContainer .find('i').removeClass ('fa-thumbs-
down').addClass ('fa-thumbs-o-down');

dislikeContainer .find('span').text(parseInt (dislikeContainer .find('span'
).text(), 10) – 1);

if (commentParentList .length > 1) {
var previousComment = commentContainer .prev();
if (previousComment .length) {

previousComment .before(commentContainer .detach());
}
}
});
} else {
// adding thumbs down
$.post('../adaugare -review-comentariu' , {'id_comment' :
commentId , 'review' : '0'}, function (response){
if (!response. length) {
alert('You can NOT review your own comment!' );
return false ;
}
response = JSON.parse(response);

dislikeContainer .attr('data-review-id',
response.id_review_comment);
dislikeCont ainer.find('i').removeClass ('fa-thumbs-o-
down').addClass ('fa-thumbs-down');
dislikeContainer .find('span').text(1 +
parseInt (dislikeContainer .find('span').text(), 10));
if (commentParentList .length > 1) {
var nextComment = commentContainer .next();
if (nextComment .length) {
nextComment .after(commentContainer .detach());
}
}
// if comment was previously up -voted (an d not by
current user), remove thumbs up
var likeContainer = dislikeContainer .prev(),
likeReviewId = likeContainer .attr('data-review-id');

if (likeContainer .find('i').hasClass ('fa-thumbs-up') &&
(likeReviewId != null)) {
$.post('../stergere -review-comentariu' ,
{'id_review' : likeContainer .attr('data-review-id')}, function (){
likeContainer .removeAttr ('data-review-id');
likeContainer .find('i').removeClass ('fa-thumbs-
up').addClass ('fa-thumbs-o-up');

likeContainer .find('span').text(parseInt (likeContainer .find('span').text
(), 10) – 1);
});
}
})
}

66
});

/**–––––––
* End of Article Comments logic
* ––––––– */
});

 application/controllers/Admin_main.php (user management -ul in procesele de
logare/inregistrare/recuperare parola)
 <?php
defined('BASEPATH' ) OR exit('No direct scrip t access allowed' );

class Admin_main extends CI_Controller
{

public $status;
private $usersTable ;

function __construct()
{
parent::__construct ();
$this->load->model('User_model' , 'user_model' , TRUE);
$this->load->library( 'form_validation' );
$this->form_validation ->set_error_delimiters( '<div
class="error">' , '</div>' );
$this->status = $this->config->item('status' );
$this->usersTable = 'company' ;
}

public function index()
{
if (empty($this->session->userdata ['id'])) {
redirect(site_url() . 'admin/login/' );
}

$this->load->model('Company_model' , 'company_model' , TRUE);
$this->load->model('Student_model' , 'student_model' , TRUE);

$this->load->view('admin/page_home' , array('pending_companies'
=> $this->company_model ->get_pending_companies(), 'pending_students' =>
$this->student_model ->get_pending_students()));
}

public function register()
{
$this->form_validation ->set_rules( 'name', 'Company name' ,
'required' );
$this->form_validation ->set_rules( 'email', 'Email',
'required|valid_email' );

if ($this->form_validation ->run() == FALSE) {
$this->load->view('admin/page_register' );
} else {
if ($this->user_model ->isDuplicate( $this->input-
>post('email'), $this->usersTable )) {
$this->session->set_flashdata( 'flash_message' , 'User
email already exists' );
redirect(site_url() . 'admin/login' );
} else {
// add company with pending status
$clean = $this->security ->xss_clean( $this->input-

67
>post(NULL, TRUE));
$this->user_model ->insertUser( $clean, $this-
>usersTable );

$this->session->set_flashdata( 'flash_message' , 'In
curand veti primi un email cu instructiuni pentru incheierea procesului
de inregistrare.' );
redirect(site_url() . 'admin/login' );
};
}
}

public function approve_request()
{
$id = $this->input->post('id');
$email = $this->input->post('email');
$usersTable = $this->input->post('userTable' );
$user_approved = $this->user_model ->approveUser( $id,
$usersTable );
if ($user_approved ) {
$token = $this->user_model ->insertToken( $id, $usersTable );

$qstring = $this->base64url_encode( $token);
// create link for wither admin or front
$url = $usersTable == 'company' ? site_url() .
'admin/complete/token/' . $qstring : site_url() . 'complete/token/' .
$qstring ;
$link = '<a href="' . $url . '">link</a>' ;

echo $this->send_register_mail( $email, $link);
}
echo false ;
}

protected function send_register_mail( $to_email , $link)
{
$from = 'admin@ace.ro' ;
$subject = 'Bun venit la Forum A.C.E.' ;
$message = '<strong>Accesati urmatorul link pentru
inregistrare:</strong> ' . $link;
$footer = '<strong>Forum A.C.E.</strong><br>' ;
$footer .= '<strong >' . date('d M Y') . '</strong>' ;

$this->load->helper( 'email');
$body = get_email_template( '', $message , $footer, 'Bun venit la
Forum A.C.E.' );
return send_email( $from, $to_email , $subject , $body);
}

protected function _islocal()
{
return strpos($_SERVER ['HTTP_HOST' ], 'local');
}

public function complete( $token = false)
{
$token = base64_decode ($token);
$cleanToken = $this->security ->xss_clean( $token);

$userInfo = $this->user_model->isTokenValid( $cleanToken , $this-
>usersTable ); //either false or array();

if (!$userInfo ) {
$this->session->set_flashdata( 'flash_message' , 'Token is
invalid or expired' );
redirect(site_url() . 'admin/login' );

68
}
$data = array(
'name' => $userInfo ->name,
'email' => $userInfo ->email,
'user_id' => $userInfo ->id,
'token' => $this->base64url_encode( $token)
);

$this->form_validation ->set_rules( 'password' , 'Password' ,
'required|min_length[5]' );
$this->form_validation ->set_rules( 'passconf' , 'Password
Confirmation' , 'required|matches[password]' );

if ($this->form_validation ->run() == FALSE) {
$this->load->view('admin/pag e_complete' , $data);
} else {
$this->load->library( 'password' );
$post = $this->input->post(NULL, TRUE);

$cleanPost = $this->security ->xss_clean( $post);

$hashed = $this->password –
>create_hash( $cleanPost ['password' ]);
$cleanPost ['password' ] = $hashed;
unset($cleanPost ['passconf' ]);
$userInfo = $this->user_model ->updateUserInfo( $cleanPost ,
$this->usersTable );

if (!$userInfo ) {
$this->session->set_flashdata( 'flash_message' , 'There
was a problem updating your record' );
redirect(site_url() . 'admin/login' );
}

unset($userInfo ->password );
// just in case the last logged in user was the admin
$this->session->set_userdata( 'role', 'company' );
foreach ($userInfo as $key => $val) {
$this->session->set_userdata( $key, $val);
}
redirect(site_url() . 'admin');
}
}

public function login()
{
// if somehow the user is logged but he's accessing the login
page, redirect him to home page
if (!empty($this->session->userdata ['id'])) {
/*go to home page*/
redirect(site_url() . 'admin');
}

$this->form_validation ->set_rules( 'email', 'Email',
'required|valid_email' );
$this->form_validation ->set_rules( 'password' , 'Password' ,
'required' );

if ($this->form_validation ->run() == FALSE) {
$this->load->view('admin/page_login' );
} else {
$post = $this->input->post();
$clean = $this->security ->xss_clean( $post);
// first check if user is admin
if (!$userInfo = $this->user_model ->checkLogin( $clean,
'backend_user' )) {

69
// if not, check if company
$userInfo = $this->user_model ->checkLogin( $clean, $this-
>usersTable );
}

if (!$userInfo ) {
$this->session->set_flashdata( 'flash_message' , 'The
login was unsuccessful' );
redirect(site_url() . 'admin');
}
foreach ($userInfo as $key => $val) {
$this->session->set_userdata( $key, $val);
}
redirect(site_url() . 'admin');
}
}

public function logout()
{
$this->session->sess_destroy();
redirect(site_url() . 'admin/login' );
}

public function forgot()
{
$this->form_validation ->set_rules( 'email', 'Email',
'required|val id_email' );

if ($this->form_validation ->run() == FALSE) {
$this->load->view('admin/page_forgot' );
} else {
$email = $this->input->post('email');
$clean = $this->security ->xss_clean( $email);
$userType = 'admin';
if (!$userInfo = $this->user_model –
>getUserInfoByEmail( $clean, 'backend_user' )) {
$userType = 'company' ;
$userInfo = $this->user_model –
>getUserInfoByEmail( $clean, $this->usersTable );
}

if (!$userInfo ) {
$this->session->set_flashdata( 'flash_message' , 'We can
not find your email address' );
redirect(site_url() . 'admin/login' );
}

if ($userInfo ->status != $this->status[2]) { //if status is
not completed
$this->session->set_flashdata( 'flash_message' , 'Your
account is not in approved status' );
redirect(site_url() . 'admin/login' );
}

//build token
$token = $this->user_model ->insertToken( $userInfo ->id,
$userType );
$qstring = $this->base64url_encode( $token);
$url = site_url() . 'admin/reset_password/token/' .
$qstring ;
$link = '<a href="' . $url . '">link</a>' ;

if ($this->send_forgot_pass_email( $clean, $link)) {
// first check if user is admin
if (!$userInfo = $this->user_model ->checkLogin( $clean,
'backend_user' )) {

70
// if not, check if company
$userInfo = $this->user_model ->checkLogin( $clean, $this-
>usersTable );
}

if (!$userInfo ) {
$this->session->set_flashdata( 'flash_message' , 'The
login was unsuccessful' );
redirect(site_url() . 'admin');
}
foreach ($userInfo as $key => $val) {
$this->session->set_userdata( $key, $val);
}
redirect(site_url() . 'admin');
}
}

public function logout()
{
$this->session->sess_destro y();
redirect(site_url() . 'admin/login' );
}

public function forgot()
{
$this->form_validation ->set_rules( 'email', 'Email',
'required|valid_email' );

if ($this->form_validation ->run() == FALSE) {
$this->load->view('admin/page_forgot' );
} else {
$email = $this->input->post('email');
$clean = $this->security ->xss_clean( $email);
$userType = 'admin';
if (!$userInfo = $this->user_model –
>getUserInfoByEmail( $clean, 'backend_user' )) {
$userType = 'company' ;
$userInfo = $this->user_model –
>getUserInfoByEmail( $clean, $this->usersTable );
}

if (!$userInfo ) {
$this->session->set_flashdata( 'flash_m essage', 'We can
not find your email address' );
redirect(site_url() . 'admin/login' );
}

if ($userInfo ->status != $this->status[2]) { //if status is
not completed
$this->session->set_flashdata( 'flash_message' , 'Your
account is not in approved status' );
redirect(site_url() . 'admin/login' );
}

//build token
$token = $this->user_model ->insertToken( $userInfo ->id,
$userType );
$qstring = $this->base64url_encode( $token);
$url = site_url() . 'admin/reset_password/token/' .
$qstring ;
$link = '<a href="' . $url . '">link</a>' ;

if ($this->send_forgot_pass_email( $clean, $link)) {
$cleanPost ['user_id' ] = $userInfo ->id;
unset($cleanPost ['passconf' ]);
if (!$this->user_model ->updatePassword( $cleanPost , $table))

71
{
$this->session->set_flashdata( 'flash_message' , 'There
was a problem updating your password' );
} else {
$this->session->set_flashdata( 'flash_message' , 'Your
password has been updated. You may now login' );
}
redirect(site_url() . 'admin/login' );
}
}

public function base64url_encode( $data)
{
return rtrim(strtr(base64_encode ($data), '+/', '-_'), '=');
}

public function base64url_decode( $data)
{
return base64_decode (str_pad(strtr($data, '-_', '+/'),
strlen($data) % 4, '=', STR_PAD_RIGHT ));
}

public function get_user_profile()
{
$userSession = $this->session->userdata ;
if (empty($userSession ['id'])) {
redirect(site_url() . 'admin/login' );
}

$this->load->view('admin/page_profile' , array('user' =>
$userSession ));
}

}

B. CD / DVD
A dvd with the presentation and dissertation paper has been included.

Similar Posts