add dns form
	
		
			
	
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
					Details
				
			
		
	
				
					
				
			
				
	
				continuous-integration/drone/push Build is passing
				
					Details
				
			
		
	This commit is contained in:
		
							parent
							
								
									b2fa4fe945
								
							
						
					
					
						commit
						75ba836d60
					
				|  | @ -0,0 +1,23 @@ | |||
| package api | ||||
| 
 | ||||
| import ( | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database" | ||||
| ) | ||||
| 
 | ||||
| func ListDNSRecordsContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| 		dnsRecords, err := database.GetUserDNSRecords(context.DBConn, context.User.ID) | ||||
| 		if err != nil { | ||||
| 			log.Println(err) | ||||
| 			resp.WriteHeader(http.StatusInternalServerError) | ||||
| 			return failure(context, req, resp) | ||||
| 		} | ||||
| 
 | ||||
| 		(*context.TemplateData)["DNSRecords"] = dnsRecords | ||||
| 
 | ||||
| 		return success(context, req, resp) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										14
									
								
								api/serve.go
								
								
								
								
							
							
						
						
									
										14
									
								
								api/serve.go
								
								
								
								
							|  | @ -19,7 +19,8 @@ type RequestContext struct { | |||
| 	Id    string | ||||
| 	Start time.Time | ||||
| 
 | ||||
| 	User *database.User | ||||
| 	TemplateData *map[string]interface{} | ||||
| 	User         *database.User | ||||
| } | ||||
| 
 | ||||
| type Continuation func(*RequestContext, *http.Request, http.ResponseWriter) ContinuationChain | ||||
|  | @ -75,12 +76,14 @@ func MakeServer(argv *args.Arguments, dbConn *sql.DB) *http.Server { | |||
| 		return &RequestContext{ | ||||
| 			DBConn: dbConn, | ||||
| 			Args:   argv, | ||||
| 
 | ||||
| 			TemplateData: &map[string]interface{}{}, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(TemplateContinuation("home.html", nil, true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(TemplateContinuation("home.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("GET /api/health", func(w http.ResponseWriter, r *http.Request) { | ||||
|  | @ -108,10 +111,15 @@ func MakeServer(argv *args.Arguments, dbConn *sql.DB) *http.Server { | |||
| 		LogRequestContinuation(requestContext, r, w)(LogoutContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("GET /dns", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(ListDNSRecordsContinuation, GoLoginContinuation)(TemplateContinuation("dns.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("GET /{name}", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		name := r.PathValue("name") | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(TemplateContinuation(name+".html", nil, true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(TemplateContinuation(name+".html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	return &http.Server{ | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ import ( | |||
| 	"os" | ||||
| ) | ||||
| 
 | ||||
| func renderTemplate(context *RequestContext, templateName string, showBaseHtml bool, data interface{}) (bytes.Buffer, error) { | ||||
| func renderTemplate(context *RequestContext, templateName string, showBaseHtml bool) (bytes.Buffer, error) { | ||||
| 	templatePath := context.Args.TemplatePath | ||||
| 	basePath := templatePath + "/base_empty.html" | ||||
| 	if showBaseHtml { | ||||
|  | @ -22,11 +22,14 @@ func renderTemplate(context *RequestContext, templateName string, showBaseHtml b | |||
| 		return bytes.Buffer{}, err | ||||
| 	} | ||||
| 
 | ||||
| 	if data == nil { | ||||
| 		data = map[string]interface{}{} | ||||
| 	dataPtr := context.TemplateData | ||||
| 	if dataPtr == nil { | ||||
| 		dataPtr = &map[string]interface{}{} | ||||
| 	} | ||||
| 	if context.User != nil { | ||||
| 		data.(map[string]interface{})["User"] = context.User | ||||
| 
 | ||||
| 	data := *dataPtr | ||||
| 	if data["User"] == nil { | ||||
| 		data["User"] = context.User | ||||
| 	} | ||||
| 
 | ||||
| 	var buffer bytes.Buffer | ||||
|  | @ -38,13 +41,13 @@ func renderTemplate(context *RequestContext, templateName string, showBaseHtml b | |||
| 	return buffer, nil | ||||
| } | ||||
| 
 | ||||
| func TemplateContinuation(path string, data interface{}, showBase bool) Continuation { | ||||
| func TemplateContinuation(path string, showBase bool) Continuation { | ||||
| 	return func(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 		return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| 			html, err := renderTemplate(context, path, true, data) | ||||
| 			html, err := renderTemplate(context, path, true) | ||||
| 			if errors.Is(err, os.ErrNotExist) { | ||||
| 				resp.WriteHeader(404) | ||||
| 				html, err = renderTemplate(context, "404.html", true, nil) | ||||
| 				html, err = renderTemplate(context, "404.html", true) | ||||
| 				if err != nil { | ||||
| 					log.Println("error rendering 404 template", err) | ||||
| 					resp.WriteHeader(500) | ||||
|  |  | |||
|  | @ -0,0 +1,40 @@ | |||
| package database | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	_ "github.com/mattn/go-sqlite3" | ||||
| 	"log" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type DNSRecord struct { | ||||
| 	ID        string | ||||
| 	UserID    string | ||||
| 	Name      string | ||||
| 	Type      string | ||||
| 	Content   string | ||||
| 	TTL       int | ||||
| 	CreatedAt time.Time | ||||
| } | ||||
| 
 | ||||
| func GetUserDNSRecords(db *sql.DB, userID string) ([]DNSRecord, error) { | ||||
| 	log.Println("getting dns records for user", userID) | ||||
| 
 | ||||
| 	rows, err := db.Query("SELECT * FROM dns_records WHERE user_id = ?", userID) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer rows.Close() | ||||
| 
 | ||||
| 	var records []DNSRecord | ||||
| 	for rows.Next() { | ||||
| 		var record DNSRecord | ||||
| 		err := rows.Scan(&record.ID, &record.UserID, &record.Name, &record.Type, &record.Content, &record.TTL, &record.CreatedAt) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		records = append(records, record) | ||||
| 	} | ||||
| 
 | ||||
| 	return records, nil | ||||
| } | ||||
|  | @ -1,25 +1,33 @@ | |||
| :root { | ||||
|   --background-color-light: #f4e8e9; | ||||
|   --background-color-light-2: #f7f7f7; | ||||
|   --text-color-light: #333; | ||||
|   --link-color-light: #d291bc; | ||||
|   --container-bg-light: #fff7f8; | ||||
|   --container-bg-light: #fff7f87a; | ||||
|   --border-color-light: #692fcc; | ||||
| 
 | ||||
|   --background-color-dark: #333; | ||||
|   --background-color-dark-2: #2c2c2c; | ||||
|   --text-color-dark: #f4e8e9; | ||||
|   --link-color-dark: #b86b77; | ||||
|   --container-bg-dark: #424242; | ||||
|   --container-bg-dark: #424242ea; | ||||
|   --border-color-dark: #956ade; | ||||
| } | ||||
| 
 | ||||
| [data-theme="DARK"] { | ||||
|   --background-color: var(--background-color-dark); | ||||
|   --background-color-2: var(--background-color-dark-2); | ||||
|   --text-color: var(--text-color-dark); | ||||
|   --link-color: var(--link-color-dark); | ||||
|   --container-bg: var(--container-bg-dark); | ||||
|   --border-color: var(--border-color-dark); | ||||
| } | ||||
| 
 | ||||
| [data-theme="LIGHT"] { | ||||
|   --background-color: var(--background-color-light); | ||||
|   --background-color-2: var(--background-color-light-2); | ||||
|   --text-color: var(--text-color-light); | ||||
|   --link-color: var(--link-color-light); | ||||
|   --container-bg: var(--container-bg-light); | ||||
|   --border-color: var(--border-color-light); | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,30 @@ | |||
| form { | ||||
|   max-width: 600px; | ||||
|   padding: 1em; | ||||
|   background: var(--background-color-2); | ||||
|   border: 1px solid #ccc; | ||||
| } | ||||
| 
 | ||||
| label { | ||||
|   display: block; | ||||
|   margin: 0 0 1em; | ||||
|   font-weight: bold; | ||||
| } | ||||
| 
 | ||||
| input { | ||||
|   display: block; | ||||
|   width: 100%; | ||||
|   padding: 0.5em; | ||||
|   margin: 0 0 1em; | ||||
|   border: 1px solid var(--border-color); | ||||
|   background: var(--container-bg); | ||||
| } | ||||
| 
 | ||||
| button, | ||||
| input[type="submit"] { | ||||
|   padding: 0.5em 1em; | ||||
|   background: var(--link-color); | ||||
|   color: var(--text-color); | ||||
|   border: 0; | ||||
|   cursor: pointer; | ||||
| } | ||||
|  | @ -1,5 +1,7 @@ | |||
| @import "/static/css/colors.css"; | ||||
| @import "/static/css/blinky.css"; | ||||
| @import "/static/css/table.css"; | ||||
| @import "/static/css/form.css"; | ||||
| 
 | ||||
| @font-face { | ||||
|   font-family: "ComicSans"; | ||||
|  | @ -11,10 +13,10 @@ | |||
|   margin: 0; | ||||
|   padding: 0; | ||||
|   color: var(--text-color); | ||||
|   font-family: "ComicSans", sans-serif; | ||||
| } | ||||
| 
 | ||||
| body { | ||||
|   font-family: "ComicSans", sans-serif; | ||||
|   background-color: var(--background-color); | ||||
|   background-image: url("/static/img/stars.gif"); | ||||
|   min-height: 100vh; | ||||
|  | @ -35,7 +37,6 @@ a:hover { | |||
|   margin: auto; | ||||
|   background-color: var(--container-bg); | ||||
|   padding: 1rem; | ||||
|   opacity: 0.95; | ||||
| } | ||||
| 
 | ||||
| hr { | ||||
|  | @ -44,3 +45,11 @@ hr { | |||
| 
 | ||||
|   margin: 20px 0; | ||||
| } | ||||
| 
 | ||||
| .blinkies { | ||||
|   display: flex; | ||||
|   justify-content: left; | ||||
|   flex-wrap: wrap; | ||||
|   max-width: 900px; | ||||
|   gap: 10px 10px; | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| table { | ||||
|   width: auto; | ||||
|   border-collapse: collapse; | ||||
|   border: 1px solid var(--border-color); | ||||
| } | ||||
| 
 | ||||
| th, | ||||
| td { | ||||
|   padding: 12px 20px; | ||||
|   text-align: left; | ||||
|   border-bottom: 1px solid var(--border-color); | ||||
| } | ||||
| 
 | ||||
| tbody tr:nth-child(odd) { | ||||
|   background-color: var(--link-color); | ||||
|   color: var(--text-color); | ||||
| } | ||||
| 
 | ||||
| tbody tr { | ||||
|   transition: background-color 0.3s ease; | ||||
| } | ||||
| 
 | ||||
| tbody tr:hover { | ||||
|   background-color: #ff47daa0; | ||||
|   color: #2a2a2a; | ||||
| } | ||||
|  | @ -50,6 +50,21 @@ | |||
| 
 | ||||
|       <div class="footer"> | ||||
| 	<div> | ||||
| 	  {{ if .User }} | ||||
| 	  <a href="https://git.hatecomputers.club/{{ .User.Username }}">git.</a> | ||||
| 	  {{ else }} | ||||
| 	  <a href="https://git.hatecomputers.club">git.</a> | ||||
| 	  {{ end }} | ||||
| 
 | ||||
| 	  <span> | </span> | ||||
| 	  <a href="https://mail.hatecomputers.club">e-mail.</a> | ||||
| 	  <span> | </span> | ||||
| 	  <a href="https://auth.hatecomputers.club">sso.</a> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<br> | ||||
| 
 | ||||
| 	<div class="blinkies"> | ||||
| 	  <img width='150' height='20' src='/static/img/blinkies/hatecomputers-club.gif'> | ||||
| 	  <img width='150' height='20' src='/static/img/blinkies/autism.gif'> | ||||
| 	  <img width='150' height='20' src='/static/img/blinkies/fuckcomputers.gif'> | ||||
|  | @ -60,17 +75,6 @@ | |||
| 	  <img width='150' height='20' src='/static/img/blinkies/eepy.gif'> | ||||
| 	  <img width='150' height='20' src='/static/img/blinkies/loveuguys.gif'> | ||||
| 	</div> | ||||
| 	 | ||||
| 	{{ if .User }} | ||||
| 	<a href="https://git.hatecomputers.club/{{ .User.Username }}">git.</a> | ||||
| 	{{ else }} | ||||
| 	<a href="https://git.hatecomputers.club">git.</a> | ||||
| 	{{ end }} | ||||
| 
 | ||||
| 	<span> | </span> | ||||
| 	<a href="https://mail.hatecomputers.club">e-mail.</a> | ||||
| 	<span> | </span> | ||||
| 	<a href="https://auth.hatecomputers.club">sso.</a> | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,37 @@ | |||
| {{ define "content" }} | ||||
|   <table> | ||||
|     <tr> | ||||
|       <th>Type</th> | ||||
|       <th>Name</th> | ||||
|       <th>Content</th> | ||||
|       <th>TTL</th> | ||||
|     </tr> | ||||
|     {{ if (eq (len .DNSRecords) 0) }} | ||||
|     <tr> | ||||
|       <td colspan="4"><span class="blinky">No DNS records found</span></td> | ||||
|     </tr> | ||||
|     {{ end }} | ||||
|     {{ range $record := .DNSRecords }} | ||||
|       <tr> | ||||
| 	<td>{{ $record.Type }}</td> | ||||
| 	<td>{{ $record.Name }}</td> | ||||
| 	<td>{{ $record.Content }}</td> | ||||
| 	<td>{{ $record.TTL }}</td> | ||||
|       </tr> | ||||
|     {{ end }} | ||||
|   </table> | ||||
|   <br> | ||||
|   <form method="POST" action="/dns"> | ||||
|     <h2>Add DNS Records</h2> | ||||
|     <hr> | ||||
|     <label for="type">Type</label> | ||||
|     <input type="text" name="type" placeholder="CNAME" required /> | ||||
|     <label for="name">Name</label> | ||||
|     <input type="text" name="name" placeholder="{{ .User.Username }}" required /> | ||||
|     <label for="content">Content</label> | ||||
|     <input type="text" name="content" placeholder="{{ .User.Username }}.dev" required /> | ||||
|     <label for="ttl">TTL</label> | ||||
|     <input type="text" name="ttl" placeholder="43200" required /> | ||||
|     <input type="submit" value="Add" /> | ||||
|   </form> | ||||
| {{ end }} | ||||
		Loading…
	
		Reference in New Issue