1package projects
2
3import (
4	"database/sql"
5	"encoding/json"
6	"net/http"
7
8	"github.com/ansible-semaphore/semaphore/db"
9
10	"github.com/ansible-semaphore/semaphore/util"
11	"github.com/gorilla/context"
12	"github.com/masterminds/squirrel"
13)
14
15// EnvironmentMiddleware ensures an environment exists and loads it to the context
16func EnvironmentMiddleware(next http.Handler) http.Handler {
17	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
18		project := context.Get(r, "project").(db.Project)
19		envID, err := util.GetIntParam("environment_id", w, r)
20		if err != nil {
21			return
22		}
23
24		query, args, err := squirrel.Select("*").
25			From("project__environment").
26			Where("project_id=?", project.ID).
27			Where("id=?", envID).
28			ToSql()
29		util.LogWarning(err)
30
31		var env db.Environment
32		if err := db.Mysql.SelectOne(&env, query, args...); err != nil {
33			if err == sql.ErrNoRows {
34				w.WriteHeader(http.StatusNotFound)
35				return
36			}
37
38			panic(err)
39		}
40
41		context.Set(r, "environment", env)
42		next.ServeHTTP(w, r)
43	})
44}
45
46// GetEnvironment retrieves sorted environments from the database
47func GetEnvironment(w http.ResponseWriter, r *http.Request) {
48	if environment := context.Get(r, "environment"); environment != nil {
49		util.WriteJSON(w, http.StatusOK, environment.(db.Environment))
50		return
51	}
52
53	project := context.Get(r, "project").(db.Project)
54	var env []db.Environment
55
56	sort := r.URL.Query().Get("sort")
57	order := r.URL.Query().Get("order")
58
59	if order != "asc" && order != "desc" {
60		order = "asc"
61	}
62
63	q := squirrel.Select("*").
64		From("project__environment pe").
65		Where("project_id=?", project.ID)
66
67	switch sort {
68	case "name":
69		q = q.Where("pe.project_id=?", project.ID).
70			OrderBy("pe." + sort + " " + order)
71	default:
72		q = q.Where("pe.project_id=?", project.ID).
73			OrderBy("pe.name " + order)
74	}
75
76	query, args, err := q.ToSql()
77	util.LogWarning(err)
78
79	if _, err := db.Mysql.Select(&env, query, args...); err != nil {
80		panic(err)
81	}
82
83	util.WriteJSON(w, http.StatusOK, env)
84}
85
86// UpdateEnvironment updates an existing environment in the database
87func UpdateEnvironment(w http.ResponseWriter, r *http.Request) {
88	oldEnv := context.Get(r, "environment").(db.Environment)
89	var env db.Environment
90	if err := util.Bind(w, r, &env); err != nil {
91		return
92	}
93
94	var js map[string]interface{}
95	if json.Unmarshal([]byte(env.JSON), &js) != nil {
96		util.WriteJSON(w, http.StatusBadRequest, map[string]string{
97			"error": "JSON is not valid",
98		})
99		return
100	}
101
102	if _, err := db.Mysql.Exec("update project__environment set name=?, json=? where id=?", env.Name, env.JSON, oldEnv.ID); err != nil {
103		panic(err)
104	}
105
106	w.WriteHeader(http.StatusNoContent)
107}
108
109// AddEnvironment creates an environment in the database
110func AddEnvironment(w http.ResponseWriter, r *http.Request) {
111	project := context.Get(r, "project").(db.Project)
112	var env db.Environment
113
114	if err := util.Bind(w, r, &env); err != nil {
115		return
116	}
117
118	var js map[string]interface{}
119	if json.Unmarshal([]byte(env.JSON), &js) != nil {
120		util.WriteJSON(w, http.StatusBadRequest, map[string]string{
121			"error": "JSON is not valid",
122		})
123		return
124	}
125
126	res, err := db.Mysql.Exec("insert into project__environment set project_id=?, name=?, json=?, password=?", project.ID, env.Name, env.JSON, env.Password)
127	if err != nil {
128		panic(err)
129	}
130
131	insertID, err := res.LastInsertId()
132	util.LogWarning(err)
133	insertIDInt := int(insertID)
134	objType := "environment"
135
136	desc := "Environment " + env.Name + " created"
137	if err := (db.Event{
138		ProjectID:   &project.ID,
139		ObjectType:  &objType,
140		ObjectID:    &insertIDInt,
141		Description: &desc,
142	}.Insert()); err != nil {
143		panic(err)
144	}
145
146	w.WriteHeader(http.StatusNoContent)
147}
148
149// RemoveEnvironment deletes an environment from the database
150func RemoveEnvironment(w http.ResponseWriter, r *http.Request) {
151	env := context.Get(r, "environment").(db.Environment)
152
153	templatesC, err := db.Mysql.SelectInt("select count(1) from project__template where project_id=? and environment_id=?", env.ProjectID, env.ID)
154	if err != nil {
155		panic(err)
156	}
157
158	if templatesC > 0 {
159		if len(r.URL.Query().Get("setRemoved")) == 0 {
160			util.WriteJSON(w, http.StatusBadRequest, map[string]interface{}{
161				"error": "Environment is in use by one or more templates",
162				"inUse": true,
163			})
164
165			return
166		}
167
168		if _, err := db.Mysql.Exec("update project__environment set removed=1 where id=?", env.ID); err != nil {
169			panic(err)
170		}
171
172		w.WriteHeader(http.StatusNoContent)
173		return
174	}
175
176	if _, err := db.Mysql.Exec("delete from project__environment where id=?", env.ID); err != nil {
177		panic(err)
178	}
179
180	desc := "Environment " + env.Name + " deleted"
181	if err := (db.Event{
182		ProjectID:   &env.ProjectID,
183		Description: &desc,
184	}.Insert()); err != nil {
185		panic(err)
186	}
187
188	w.WriteHeader(http.StatusNoContent)
189}
190