Beispiel #1
1
func renderContactForm(c *reqContext, context template.Context,
	formValues url.Values, h *nodeHandler) error {
	G, _, _, _ := gettext.DefaultLocales.Use("",
		c.SiteSettings.Fields["core.Locale"].Value().(string))
	m := c.Serv.Monsti()
	data := contactFormData{}
	form := htmlwidgets.NewForm(&data)
	form.AddWidget(&htmlwidgets.TextWidget{MinLength: 1,
		ValidationError: G("Required.")}, "Name", G("Name"), "")
	form.AddWidget(&htmlwidgets.TextWidget{MinLength: 1,
		ValidationError: G("Required.")}, "Email", G("Email"), "")
	form.AddWidget(&htmlwidgets.TextWidget{MinLength: 1,
		ValidationError: G("Required.")}, "Subject", G("Subject"), "")
	form.AddWidget(&htmlwidgets.TextAreaWidget{MinLength: 1,
		ValidationError: G("Required.")}, "Message", G("Message"), "")

	switch c.Req.Method {
	case "GET":
		if _, submitted := formValues["submitted"]; submitted {
			context["Submitted"] = 1
		}
	case "POST":
		if form.Fill(formValues) {
			mail := gomail.NewMessage()
			mail.SetAddressHeader("From",
				c.SiteSettings.StringValue("core.EmailAddress"),
				c.SiteSettings.StringValue("core.EmailName"))
			mail.SetAddressHeader("To",
				c.SiteSettings.StringValue("core.OwnerEmail"),
				c.SiteSettings.StringValue("core.OwnerName"))
			mail.SetAddressHeader("Reply-To", data.Email, data.Name)
			mail.SetHeader("Subject", data.Subject)
			body := fmt.Sprintf("%v\n%v\n\n%v",
				fmt.Sprintf(G("Received from contact form at %v"),
					c.SiteSettings.StringValue("core.Title")),
				fmt.Sprintf(G("Name: %v | Email: %v"), data.Name, data.Email),
				data.Message)
			mail.SetBody("text/plain", body)
			mailer := gomail.NewCustomMailer("", nil, gomail.SetSendMail(
				m.SendMailFunc()))
			err := mailer.Send(mail)
			if err != nil {
				return fmt.Errorf("Could not send mail: %v", err)
			}
			http.Redirect(c.Res, c.Req, path.Dir(c.Node.Path)+"/?submitted", http.StatusSeeOther)
			return nil
		}
	default:
		return fmt.Errorf("Request method not supported: %v", c.Req.Method)
	}
	context["Form"] = form.RenderData()
	return nil
}
Beispiel #2
0
// Remove handles remove requests.
func (h *nodeHandler) Remove(c *reqContext) error {
	G, _, _, _ := gettext.DefaultLocales.Use("", c.UserSession.Locale)
	data := removeFormData{}
	form := htmlwidgets.NewForm(&data)
	form.AddWidget(new(htmlwidgets.HiddenWidget), "Confirm", G("Confirm"), "")
	switch c.Req.Method {
	case "GET":
		data.Confirm = "ok"
	case "POST":
		if form.Fill(c.Req.Form) && data.Confirm == "ok" {
			if err := c.Serv.Monsti().RemoveNode(c.Site, c.Node.Path); err != nil {
				return fmt.Errorf("Could not remove node: %v", err)
			}
			http.Redirect(c.Res, c.Req, path.Dir(c.Node.Path), http.StatusSeeOther)
			return nil
		}
	default:
		return fmt.Errorf("Request method not supported: %v", c.Req.Method)
	}
	body, err := h.Renderer.Render("actions/removeform", mtemplate.Context{
		"Form": form.RenderData(), "Node": c.Node},
		c.UserSession.Locale, h.Settings.Monsti.GetSiteTemplatesPath(c.Site))
	if err != nil {
		panic("Can't render node remove formular: " + err.Error())
	}
	env := masterTmplEnv{Node: c.Node, Session: c.UserSession,
		Flags: EDIT_VIEW, Title: G("Remove node")}
	rendered, _ := renderInMaster(h.Renderer, []byte(body), env, h.Settings,
		c.Site, c.SiteSettings, c.UserSession.Locale, c.Serv)
	c.Res.Write(rendered)
	return nil
}
Beispiel #3
0
// Add handles add requests.
func (h *nodeHandler) Add(c *reqContext) error {
	G, _, _, _ := gettext.DefaultLocales.Use("", c.UserSession.Locale)
	data := addFormData{New: "1"}
	nodeTypeOptions := []htmlwidgets.SelectOption{}
	nodeTypes, err := c.Serv.Monsti().GetAddableNodeTypes(c.Site.Name,
		c.Node.Type.Id)
	if err != nil {
		return fmt.Errorf("Could not get addable node types: %v", err)
	}
	for _, id := range nodeTypes {
		nodeType, err := c.Serv.Monsti().GetNodeType(id)
		if err != nil {
			return fmt.Errorf("Could not get node type: %v", err)
		}
		nodeTypeOptions = append(nodeTypeOptions,
			htmlwidgets.SelectOption{nodeType.Id,
				nodeType.GetLocalName(c.UserSession.Locale), false})
	}
	form := htmlwidgets.NewForm(&data)
	form.AddWidget(&htmlwidgets.SelectWidget{Options: nodeTypeOptions},
		"NodeType", G("Content type"), "")
	form.AddWidget(new(htmlwidgets.HiddenWidget), "New", "", "")
	form.Action = path.Join(c.Node.Path, "@@edit")
	body, err := h.Renderer.Render("actions/addform", mtemplate.Context{
		"Form": form.RenderData()}, c.UserSession.Locale,
		h.Settings.Monsti.GetSiteTemplatesPath(c.Site.Name))
	if err != nil {
		return fmt.Errorf("Can't render node add formular: %v", err)
	}
	env := masterTmplEnv{Node: c.Node, Session: c.UserSession,
		Flags: EDIT_VIEW, Title: G("Add content")}
	fmt.Fprint(c.Res, renderInMaster(h.Renderer, []byte(body), env, h.Settings,
		*c.Site, c.UserSession.Locale, c.Serv))
	return nil
}
Beispiel #4
0
// Login handles login requests.
func (h *nodeHandler) Login(c *reqContext) error {
	G, _, _, _ := gettext.DefaultLocales.Use("", c.UserSession.Locale)
	data := loginFormData{}

	form := htmlwidgets.NewForm(&data)
	form.AddWidget(new(htmlwidgets.TextWidget), "Login", G("User name"), "")
	form.AddWidget(new(htmlwidgets.PasswordWidget), "Password", G("Password"), "")

	switch c.Req.Method {
	case "GET":
	case "POST":
		if form.Fill(c.Req.Form) {
			user, err := getUser(data.Login,
				h.Settings.Monsti.GetSiteDataPath(c.Site))
			if err != nil {
				return fmt.Errorf("Could not get user: %v", err)
			}
			if user != nil && passwordEqual(user.Password, data.Password) {
				c.Session.Values["login"] = user.Login
				c.Session.Save(c.Req, c.Res)
				http.Redirect(c.Res, c.Req, c.Node.Path+"/", http.StatusSeeOther)
				return nil
			}
			form.AddError("", G("Wrong login or password."))
		}
	default:
		return fmt.Errorf("Request method not supported: %v", c.Req.Method)
	}
	data.Password = ""

	body, err := h.Renderer.Render("actions/loginform", template.Context{
		"Form": form.RenderData()}, c.UserSession.Locale,
		h.Settings.Monsti.GetSiteTemplatesPath(c.Site))
	if err != nil {
		return fmt.Errorf("Can't render login form: %v", err)
	}
	env := masterTmplEnv{Node: c.Node, Session: c.UserSession, Title: G("Login"),
		Description: G("Login with your site account."),
		Flags:       EDIT_VIEW}
	rendered, _ := renderInMaster(h.Renderer, []byte(body), env, h.Settings,
		c.Site, c.SiteSettings, c.UserSession.Locale, c.Serv)
	c.Res.Write(rendered)
	return nil
}
Beispiel #5
0
func renderContactForm(c *reqContext, context template.Context,
	formValues url.Values, h *nodeHandler) error {
	G, _, _, _ := gettext.DefaultLocales.Use("", c.Site.Locale)
	data := contactFormData{}
	form := htmlwidgets.NewForm(&data)
	form.AddWidget(&htmlwidgets.TextWidget{MinLength: 1,
		ValidationError: G("Required.")}, "Name", G("Name"), "")
	form.AddWidget(&htmlwidgets.TextWidget{MinLength: 1,
		ValidationError: G("Required.")}, "Email", G("Email"), "")
	form.AddWidget(&htmlwidgets.TextWidget{MinLength: 1,
		ValidationError: G("Required.")}, "Subject", G("Subject"), "")
	form.AddWidget(&htmlwidgets.TextAreaWidget{MinLength: 1,
		ValidationError: G("Required.")}, "Message", G("Message"), "")

	switch c.Req.Method {
	case "GET":
		if _, submitted := formValues["submitted"]; submitted {
			context["Submitted"] = 1
		}
	case "POST":
		if form.Fill(formValues) {
			mail := mimemail.Mail{
				From:    mimemail.Address{data.Name, data.Email},
				Subject: data.Subject,
				Body:    []byte(data.Message)}
			site := h.Settings.Monsti.Sites[c.Site.Name]
			owner := mimemail.Address{site.Owner.Name, site.Owner.Email}
			mail.To = []mimemail.Address{owner}
			err := c.Serv.Monsti().SendMail(&mail)
			if err != nil {
				return fmt.Errorf("Could not send mail: %v", err)
			}
			http.Redirect(c.Res, c.Req, path.Dir(c.Node.Path)+"/?submitted", http.StatusSeeOther)
			return nil
		}
	default:
		return fmt.Errorf("Request method not supported: %v", c.Req.Method)
	}
	context["Form"] = form.RenderData()
	return nil
}
Beispiel #6
0
// ChangePassword allows to change the user's password.
func (h *nodeHandler) ChangePassword(c *reqContext) error {
	G, _, _, _ := gettext.DefaultLocales.Use("", c.UserSession.Locale)
	authenticated := c.UserSession.User != nil
	data := changePasswordFormData{}
	form := htmlwidgets.NewForm(&data)
	if authenticated {
		form.AddWidget(&htmlwidgets.PasswordWidget{}, "OldPassword",
			G("Old Password"), "")
	}
	form.AddWidget(&htmlwidgets.PasswordWidget{
		VerifyLabel: G("Please repeat the password."),
		VerifyError: G("Passwords do not match."),
	}, "Password", G("New Password"), "")
	var token string
	tokenInvalid := false
	c.Req.ParseForm()
	var user *service.User
	if !authenticated {
		if tokens, ok := c.Req.Form["token"]; ok {
			token = tokens[0]
		}
		if len(token) == 0 {
			http.Redirect(c.Res, c.Req, "@@login", http.StatusSeeOther)
			return nil
		}
		getUserFn := func(login string) (*service.User, error) {
			return getUser(login, h.Settings.Monsti.GetSiteDataPath(c.Site.Name))
		}
		var err error
		user, err = verifyRequestPasswordToken(
			c.Site.Name, getUserFn, c.Site.PasswordTokenKey, token)
		if err != nil {
			return fmt.Errorf("Could not verify request password token: %v", err)
		}
		if user == nil {
			tokenInvalid = true
		}
	} else {
		user = c.UserSession.User
	}
	changed := false
	switch c.Req.Method {
	case "GET":
		if _, ok := c.Req.Form["changed"]; ok {
			changed = true
		}
	case "POST":
		if authenticated || !tokenInvalid {
			if form.Fill(c.Req.Form) {
				changePassword := true
				if authenticated {
					changePassword = passwordEqual(user.Password,
						data.OldPassword)
					if !changePassword {
						form.AddError("Password", G("Wrong password."))
					}
				}
				if changePassword {
					hashed, err := bcrypt.GenerateFromPassword([]byte(data.Password), 0)
					if err != nil {
						return fmt.Errorf("Could not hash user password: %v", err)
					}
					user.PasswordChanged = time.Now().UTC()
					user.Password = string(hashed)
					err = writeUser(user, h.Settings.Monsti.GetSiteDataPath(c.Site.Name))
					if err != nil {
						return fmt.Errorf("Could not change user password: %v", err)
					}
					http.Redirect(c.Res, c.Req, "@@change-password?changed",
						http.StatusSeeOther)
					return nil
				}
			}
		}
	default:
		return fmt.Errorf("Request method not supported: %v", c.Req.Method)
	}

	body, err := h.Renderer.Render("actions/change_password",
		template.Context{
			"TokenInvalid": tokenInvalid,
			"Changed":      changed,
			"Form":         form.RenderData()}, c.UserSession.Locale,
		h.Settings.Monsti.GetSiteTemplatesPath(c.Site.Name))
	if err != nil {
		return fmt.Errorf("Can't render ChangePassword form: %v", err)
	}
	env := masterTmplEnv{
		Node:    c.Node,
		Session: c.UserSession,
		Title:   G("Change password"),
		Flags:   EDIT_VIEW}
	fmt.Fprint(c.Res, renderInMaster(h.Renderer, []byte(body), env, h.Settings,
		*c.Site, c.UserSession.Locale, c.Serv))
	return nil
}
Beispiel #7
0
// RequestPasswordToken sends the user a token to be able to change
// the login password.
func (h *nodeHandler) RequestPasswordToken(c *reqContext) error {
	G, _, _, _ := gettext.DefaultLocales.Use("", c.UserSession.Locale)
	data := requestPasswordTokenFormData{}
	form := htmlwidgets.NewForm(&data)
	form.AddWidget(new(htmlwidgets.TextWidget), "User", G("Login"), "")

	sent := false
	c.Req.ParseForm()
	switch c.Req.Method {
	case "GET":
		if _, ok := c.Req.Form["sent"]; ok {
			sent = true
		}
	case "POST":
		if form.Fill(c.Req.Form) {
			user, err := getUser(data.User,
				h.Settings.Monsti.GetSiteDataPath(c.Site.Name))
			if err != nil {
				return fmt.Errorf("Could not get user: %v", err)
			}
			if user != nil {
				site := h.Settings.Monsti.Sites[c.Site.Name]
				link := getRequestPasswordToken(c.Site.Name, data.User,
					site.PasswordTokenKey)
				mail := mimemail.Mail{
					From:    mimemail.Address{site.EmailName, site.EmailAddress},
					Subject: G("Password request"),
					Body: []byte(fmt.Sprintf(`Hello,

someone, possibly you, requested a new password for your account %v at
"%v".

To change your password, visit the following link within 24 hours.
If you did not request a new password, you may ignore this email.
%v

This is an automatically generated email. Please don't reply to it.
`, data.User, site.Title, site.BaseURL+"/@@change-password?token="+link))}
				mail.To = []mimemail.Address{mimemail.Address{user.Login, user.Email}}
				err := c.Serv.Monsti().SendMail(&mail)
				if err != nil {
					return fmt.Errorf("Could not send mail: %v", err)
				}
				http.Redirect(c.Res, c.Req, "@@request-password-token?sent",
					http.StatusSeeOther)
				return nil
			} else {
				form.AddError("User", G("Unkown user."))
			}
		}
	default:
		return fmt.Errorf("Request method not supported: %v", c.Req.Method)
	}

	body, err := h.Renderer.Render("actions/request_password_token_form",
		template.Context{
			"Sent": sent,
			"Form": form.RenderData()}, c.UserSession.Locale,
		h.Settings.Monsti.GetSiteTemplatesPath(c.Site.Name))
	if err != nil {
		return fmt.Errorf("Can't render login form: %v", err)
	}
	env := masterTmplEnv{
		Node:    c.Node,
		Session: c.UserSession,
		Title:   G("Request new password"),
		Flags:   EDIT_VIEW}
	fmt.Fprint(c.Res, renderInMaster(h.Renderer, []byte(body), env, h.Settings,
		*c.Site, c.UserSession.Locale, c.Serv))
	return nil
}
Beispiel #8
0
// RequestPasswordToken sends the user a token to be able to change
// the login password.
func (h *nodeHandler) RequestPasswordToken(c *reqContext) error {
	G, _, _, _ := gettext.DefaultLocales.Use("", c.UserSession.Locale)
	data := requestPasswordTokenFormData{}
	form := htmlwidgets.NewForm(&data)
	form.AddWidget(new(htmlwidgets.TextWidget), "User", G("Login"), "")

	sent := false
	switch c.Req.Method {
	case "GET":
		if _, ok := c.Req.Form["sent"]; ok {
			sent = true
		}
	case "POST":
		if form.Fill(c.Req.Form) {
			user, err := getUser(data.User,
				h.Settings.Monsti.GetSiteDataPath(c.Site))
			if err != nil {
				return fmt.Errorf("Could not get user: %v", err)
			}
			if user != nil {
				link := getRequestPasswordToken(c.Site, data.User,
					c.SiteSettings.StringValue("core.PasswordTokenKey"))

				// Send email to user
				mail := gomail.NewMessage()
				mail.SetAddressHeader("From",
					c.SiteSettings.StringValue("core.EmailAddress"),
					c.SiteSettings.StringValue("core.EmailName"))
				mail.SetAddressHeader("To", user.Email, user.Login)
				mail.SetHeader("Subject", G("Password request"))

				body, err := h.Renderer.Render("mails/change_password",
					template.Context{
						"SiteSettings": c.SiteSettings,
						"Account":      data.User,
						"ChangeLink": c.SiteSettings.StringValue("core.BaseURL") +
							"/@@change-password?token=" + link,
					}, c.UserSession.Locale, h.Settings.Monsti.GetSiteTemplatesPath(c.Site))
				if err != nil {
					return fmt.Errorf("Can't render password change mail: %v", err)
				}
				mail.SetBody("text/plain", string(body))
				mailer := gomail.NewCustomMailer("", nil, gomail.SetSendMail(
					c.Serv.Monsti().SendMailFunc()))
				err = mailer.Send(mail)
				if err != nil {
					return fmt.Errorf("Could not send mail: %v", err)
				}

				http.Redirect(c.Res, c.Req, "@@request-password-token?sent",
					http.StatusSeeOther)
				return nil
			} else {
				form.AddError("User", G("Unkown user."))
			}
		}
	default:
		return fmt.Errorf("Request method not supported: %v", c.Req.Method)
	}

	body, err := h.Renderer.Render("actions/request_password_token_form",
		template.Context{
			"Sent": sent,
			"Form": form.RenderData()}, c.UserSession.Locale,
		h.Settings.Monsti.GetSiteTemplatesPath(c.Site))
	if err != nil {
		return fmt.Errorf("Can't render login form: %v", err)
	}
	env := masterTmplEnv{
		Node:    c.Node,
		Session: c.UserSession,
		Title:   G("Request new password"),
		Flags:   EDIT_VIEW}
	rendered, _ := renderInMaster(h.Renderer, []byte(body), env, h.Settings,
		c.Site, c.SiteSettings, c.UserSession.Locale, c.Serv)
	c.Res.Write(rendered)
	return nil
}
Beispiel #9
0
func (h *nodeHandler) SettingsAction(c *reqContext) error {
	G, _, _, _ := gettext.DefaultLocales.Use("", c.UserSession.Locale)
	m := c.Serv.Monsti()

	settings, err := m.LoadSiteSettings(c.Site)
	if err != nil {
		return fmt.Errorf("Could not load site settings: %v", err)
	}

	formData := settingsFormData{}
	formData.Fields = make(service.NestedMap)

	form := htmlwidgets.NewForm(&formData)

	for _, field := range settings.FieldConfigs {
		if field.Hidden {
			continue
		}
		formData.Fields.Set(field.Id, settings.Fields[field.Id].FormData())
		widget := settings.Fields[field.Id].FormWidget(
			c.UserSession.Locale, field)
		form.AddWidget(widget, "Fields."+field.Id,
			field.Name.Get(c.UserSession.Locale), "")
	}

	switch c.Req.Method {
	case "GET":
	case "POST":
		if form.Fill(c.Req.Form) {
			for _, field := range settings.FieldConfigs {
				if !field.Hidden {
					settings.Fields[field.Id].FromFormData(formData.Fields.Get(field.Id))
				}
			}
			if err := m.WriteSiteSettings(c.Site, settings); err != nil {
				return fmt.Errorf("Could not update settings: %v", err)
			}
			/*
				err = m.MarkDep(
					c.Site.Name, service.CacheDep{Settings: path.Clean(settings.Path)})
				if err != nil {
					return fmt.Errorf("Could not mark settings: %v", err)
				}
			*/
			http.Redirect(c.Res, c.Req, path.Join(c.Node.Path, "@@settings?saved=1"),
				http.StatusSeeOther)
			return nil
		}
	default:
		return fmt.Errorf("Request method not supported: %v", c.Req.Method)
	}
	rendered, err := h.Renderer.Render("actions/settings",
		mtemplate.Context{
			"Form":  form.RenderData(),
			"Saved": c.Req.FormValue("saved"),
		}, c.UserSession.Locale, h.Settings.Monsti.GetSiteTemplatesPath(c.Site))

	if err != nil {
		return fmt.Errorf("Could not render settings template: %v", err)
	}

	content, _ := renderInMaster(h.Renderer, []byte(rendered),
		masterTmplEnv{Node: c.Node, Session: c.UserSession,
			Title: G("Settings"), Flags: EDIT_VIEW},
		h.Settings, c.Site, c.SiteSettings, c.UserSession.Locale, c.Serv)

	c.Res.Write(content)
	return nil
}
Beispiel #10
0
// EditNode handles node edits.
func (h *nodeHandler) Edit(c *reqContext) error {
	G, _, _, _ := gettext.DefaultLocales.Use("", c.UserSession.Locale)

	if err := c.Req.ParseMultipartForm(1024 * 1024); err != nil {
		if err != http.ErrNotMultipart {
			return fmt.Errorf("Could not parse form: %v", err)
		}
	}

	nodeType := c.Node.Type
	newNode := c.Req.Form.Get("NodeType") != ""
	if newNode {
		var err error
		nodeType, err = c.Serv.Monsti().GetNodeType(c.Req.FormValue("NodeType"))
		if err != nil {
			return fmt.Errorf("Could not get node type to add %q: %v",
				c.Req.FormValue("new"), err)
		}
		// TODO Check if node type may be added to this node
	}

	env := masterTmplEnv{Node: c.Node, Session: c.UserSession}

	if c.Action == service.EditAction {
		if newNode {
			env.Title = G("Add a new node")
		} else {
			env.Title = G("Edit node")
		}
		env.Flags = EDIT_VIEW
	}

	formData := editFormData{}
	formData.Fields = make(service.NestedMap)
	if newNode {
		formData.NodeType = nodeType.Id
		formData.Node.Type = nodeType
		err := formData.Node.InitFields(c.Serv.Monsti(), c.Site)
		if err != nil {
			return fmt.Errorf("Could not init node fields: %v", err)
		}
		formData.Node.PublishTime = time.Now().UTC()
		formData.Node.Public = true
	} else {
		formData.Node = *c.Node
	}
	form := htmlwidgets.NewForm(&formData)
	form.AddWidget(new(htmlwidgets.HiddenWidget), "NodeType", "", "")
	if !nodeType.Hide {
		form.AddWidget(new(htmlwidgets.BoolWidget), "Node.Hide", G("Hide"),
			G("Don't show node in navigation."))
	}
	form.AddWidget(new(htmlwidgets.BoolWidget), "Node.Public", G("Public"),
		G("Is the node accessible by every visitor?"))
	location, err := time.LoadLocation(c.SiteSettings.StringValue("core.Timezone"))
	if err != nil {
		location = time.UTC
	}
	form.AddWidget(&htmlwidgets.TimeWidget{
		Location: location}, "Node.PublishTime", G("Publish time"),
		G("The node won't be accessible to the public until it is published."))
	if newNode || c.Node.Name() != "" {
		form.AddWidget(&htmlwidgets.TextWidget{
			Regexp:          `^[-\w.]+$`,
			ValidationError: G("Please enter a name consisting only of the characters A-Z, a-z, 0-9, '.', and '-'")},
			"Name", G("Name"), G("The name as it should appear in the URL."))
	}
	if !newNode {
		formData.Name = c.Node.Name()
	}

	fileFields := make([]string, 0)
	for _, field := range nodeType.Fields {
		if field.Hidden {
			continue
		}
		formData.Fields.Set(field.Id, formData.Node.Fields[field.Id].FormData())
		widget := formData.Node.Fields[field.Id].FormWidget(
			c.UserSession.Locale, field)
		form.AddWidget(widget, "Fields."+field.Id,
			field.Name.Get(c.UserSession.Locale), "")
		if _, ok := field.Type.(*service.FileFieldType); ok {
			fileFields = append(fileFields, field.Id)
		}
	}

	switch c.Req.Method {
	case "GET":
	case "POST":
		if form.Fill(c.Req.Form) {
			node := formData.Node
			node.Type = nodeType
			pathPrefix := node.GetPathPrefix()
			oldPath := c.Node.Path
			parentPath := c.Node.GetParentPath()
			if newNode {
				parentPath = c.Node.Path
			}
			node.Path = path.Join(parentPath, pathPrefix, formData.Name)
			renamed := !newNode && c.Node.Name() != "" && oldPath != node.Path
			writeNode := true
			if newNode || renamed {
				existing, err := c.Serv.Monsti().GetNode(c.Site, node.Path)
				if err != nil {
					return fmt.Errorf("Could not fetch possibly existing node: %v", err)
				}
				if existing != nil {
					form.AddError("Name", G("A node with this name does already exist"))
					writeNode = false
				}
				if err = node.InitFields(c.Serv.Monsti(), c.Site); err != nil {
					return fmt.Errorf("Could not init node fields: %v", err)
				}
			}

			// Check file format for image nodes.
			if nodeType.Id == "core.Image" {
				file, _, err := c.Req.FormFile("Fields.core.File")
				if err == nil {
					content, err := ioutil.ReadAll(file)
					if err != nil {
						return fmt.Errorf("Could not read multipart file: %v", err)
					}
					if _, _, err := image.Decode(bytes.NewBuffer(content)); err != nil {
						form.AddError("Fields.core.File",
							G("Unsupported image format. Try GIF, JPEG, or PNG."))
						writeNode = false
					}
				}

			}

			if writeNode {
				if renamed {
					err := c.Serv.Monsti().RenameNode(c.Site, c.Node.Path, node.Path)
					if err != nil {
						return fmt.Errorf("Could not move node: %v", err)
					}
				}
				for _, field := range nodeType.Fields {
					if !field.Hidden {
						node.Fields[field.Id].FromFormData(formData.Fields.Get(field.Id))
					}
				}
				err := c.Serv.Monsti().WriteNode(c.Site, node.Path, &node)
				if err != nil {
					return fmt.Errorf("Could not update node: %v", err)
				}

				// Save any attached files
				if len(fileFields) > 0 && c.Req.MultipartForm != nil {
					for _, name := range fileFields {
						file, _, err := c.Req.FormFile("Fields." + name)
						if err == nil {
							content, err := ioutil.ReadAll(file)
							if err != nil {
								return fmt.Errorf("Could not read multipart file: %v", err)
							}
							if err = c.Serv.Monsti().WriteNodeData(c.Site, node.Path,
								"__file_"+name, content); err != nil {
								return fmt.Errorf("Could not save file: %v", err)
							}
						}
					}
				}
				http.Redirect(c.Res, c.Req, node.Path+"/", http.StatusSeeOther)
				err = c.Serv.Monsti().MarkDep(
					c.Site, service.CacheDep{Node: path.Clean(node.Path)})
				if err != nil {
					return fmt.Errorf("Could not mark node: %v", err)
				}
				return nil
			}
		}
	default:
		return fmt.Errorf("Request method not supported: %v", c.Req.Method)
	}
	rendered, err := h.Renderer.Render("edit",
		mtemplate.Context{"Form": form.RenderData()},
		c.UserSession.Locale, h.Settings.Monsti.GetSiteTemplatesPath(c.Site))

	if err != nil {
		return fmt.Errorf("Could not render template: %v", err)
	}

	content, _ := renderInMaster(h.Renderer, []byte(rendered), env, h.Settings,
		c.Site, c.SiteSettings, c.UserSession.Locale, c.Serv)

	c.Res.Write(content)
	return nil
}
Beispiel #11
0
func renderContactForm(req *service.Request, session *service.Session) (
	*service.RenderNodeRet, error) {

	m := session.Monsti()
	siteSettings, err := m.LoadSiteSettings(req.Site)
	if err != nil {
		return nil, fmt.Errorf("Could not get site settings: %v", err)
	}
	G, _, _, _ := gettext.DefaultLocales.Use("",
		siteSettings.Fields["core.Locale"].Value().(string))

	node, err := m.GetNode(req.Site, req.NodePath)
	if err != nil {
		return nil, fmt.Errorf("Could not get contact form node: %v", err)
	}

	data := make(service.NestedMap)
	var dataFields []dataField
	form := htmlwidgets.NewForm(data)

	formFields := node.Fields["core.ContactFormFields"].(*service.ListField)

	for i, field := range formFields.Fields {
		combinedField := field.(*service.CombinedField)
		name := combinedField.Fields["Name"].Value().(string)
		required := combinedField.Fields["Required"].Value().(bool)
		fieldId := fmt.Sprintf("field_%d", i)
		dataFields = append(dataFields, dataField{fieldId, name})
		data[fieldId] = ""
		innerFieldType := combinedField.Fields["Field"].(*service.DynamicTypeField).DynamicType
		var widget htmlwidgets.Widget
		switch innerFieldType {
		case "text":
			textWidget := &htmlwidgets.TextWidget{ValidationError: G("Required.")}
			if required {
				textWidget.MinLength = 1
			}
			widget = textWidget
		case "textarea":
			areaWidget := &htmlwidgets.TextAreaWidget{ValidationError: G("Required.")}
			if required {
				areaWidget.MinLength = 1
			}
			widget = areaWidget
		default:
			panic(fmt.Sprintf("Unknow inner field type <%v>", innerFieldType))
		}
		form.AddWidget(widget, fieldId, name, "")
	}

	if len(formFields.Fields) == 0 {
		// Add default fields for backward compatibility
		data["Name"] = ""
		data["Email"] = ""
		data["Subject"] = ""
		data["Message"] = ""
		dataFields = []dataField{
			{"Name", G("Name")},
			{"Email", G("Email")},
			{"Subject", G("Subject")},
			{"Message", G("Message")},
		}
		form.AddWidget(&htmlwidgets.TextWidget{MinLength: 1,
			ValidationError: G("Required.")}, "Name", G("Name"), "")
		form.AddWidget(&htmlwidgets.TextWidget{MinLength: 1,
			ValidationError: G("Required.")}, "Email", G("Email"), "")
		form.AddWidget(&htmlwidgets.TextWidget{MinLength: 1,
			ValidationError: G("Required.")}, "Subject", G("Subject"), "")
		form.AddWidget(&htmlwidgets.TextAreaWidget{MinLength: 1,
			ValidationError: G("Required.")}, "Message", G("Message"), "")
	}

	context := make(map[string]interface{})
	switch req.Method {
	case "GET":
		if _, submitted := req.Form["submitted"]; submitted {
			context["Submitted"] = 1
		}
	case "POST":
		if form.Fill(req.PostForm) {
			mail := gomail.NewMessage()
			mail.SetAddressHeader("From",
				siteSettings.StringValue("core.EmailAddress"),
				siteSettings.StringValue("core.EmailName"))
			mail.SetAddressHeader("To",
				siteSettings.StringValue("core.OwnerEmail"),
				siteSettings.StringValue("core.OwnerName"))
			// mail.SetAddressHeader("Reply-To", data.Email, data.Name)
			mail.SetHeader("Subject", "Contact form submission")
			var fieldValues string
			for _, v := range dataFields {
				fieldValues += fmt.Sprintf("%v: %v\n", v.Name, data[v.Id])
			}
			body := fmt.Sprintf("%v\n\n%v",
				fmt.Sprintf(G("Received from contact form at %v"),
					siteSettings.StringValue("core.Title")), fieldValues)
			mail.SetBody("text/plain", body)
			mailer := gomail.NewCustomMailer("", nil, gomail.SetSendMail(
				m.SendMailFunc()))
			err := mailer.Send(mail)
			if err != nil {
				return nil, fmt.Errorf("Could not send mail: %v", err)
			}
			return &service.RenderNodeRet{
				Redirect: &service.Redirect{
					path.Dir(node.Path) + "/?submitted", http.StatusSeeOther}}, nil
		}
	default:
		return nil, fmt.Errorf("Request method not supported: %v", req.Method)
	}
	context["Form"] = form.RenderData()
	return &service.RenderNodeRet{Context: context}, err
}
Beispiel #12
0
// EditNode handles node edits.
func (h *nodeHandler) Edit(c *reqContext) error {
	G, _, _, _ := gettext.DefaultLocales.Use("", c.UserSession.Locale)
	h.Log.Printf("(%v) %v %v", c.Site.Name, c.Req.Method, c.Req.URL.Path)

	if err := c.Req.ParseMultipartForm(1024 * 1024); err != nil {
		if err != http.ErrNotMultipart {
			return fmt.Errorf("Could not parse form: %v", err)
		}
	}

	nodeType := c.Node.Type
	newNode := len(c.Req.FormValue("NodeType")) > 0
	if newNode {
		var err error
		nodeType, err = c.Serv.Monsti().GetNodeType(c.Req.FormValue("NodeType"))
		if err != nil {
			return fmt.Errorf("Could not get node type to add %q: %v",
				c.Req.FormValue("new"), err)
		}
		// TODO Check if node type may be added to this node
	}

	env := masterTmplEnv{Node: c.Node, Session: c.UserSession}

	if c.Action == service.EditAction {
		if newNode {
			env.Title = fmt.Sprintf(G("Add %v to \"%s\""),
				nodeType.GetLocalName(c.UserSession.Locale), c.Node.Path)
		} else {
			env.Title = fmt.Sprintf(G("Edit \"%s\""), c.Node.Path)
		}
		env.Flags = EDIT_VIEW
	}

	formData := editFormData{}
	formData.Fields = make(util.NestedMap)
	if newNode {
		formData.NodeType = nodeType.Id
		formData.Node.Type = nodeType
		err := formData.Node.InitFields(c.Serv.Monsti(), c.Site.Name)
		if err != nil {
			return fmt.Errorf("Could not init node fields: %v", err)
		}
		formData.Node.PublishTime = time.Now().UTC()
		formData.Node.Public = true
	} else {
		formData.Node = *c.Node
	}
	form := htmlwidgets.NewForm(&formData)
	form.AddWidget(new(htmlwidgets.HiddenWidget), "NodeType", "", "")
	if !nodeType.Hide {
		form.AddWidget(new(htmlwidgets.BoolWidget), "Node.Hide", G("Hide"), G("Don't show node in navigation."))
	}
	form.AddWidget(new(htmlwidgets.IntegerWidget), "Node.Order", G("Order"), G("Order in navigation or listings (lower numbered entries appear first)."))
	form.AddWidget(new(htmlwidgets.BoolWidget), "Node.Public", G("Public"), G("Is the node accessible by every visitor?"))
	var timezone string
	err := c.Serv.Monsti().GetSiteConfig(c.Site.Name, "core.timezone", &timezone)
	if err != nil {
		return fmt.Errorf("Could not get timezone: %v", err)
	}
	location, err := time.LoadLocation(timezone)
	if err != nil {
		location = time.UTC
	}
	form.AddWidget(&htmlwidgets.TimeWidget{
		Location: location}, "Node.PublishTime", G("Publish time"),
		G("The node won't be accessible to the public until it is published."))
	if newNode || c.Node.Name() != "" {
		form.AddWidget(&htmlwidgets.TextWidget{
			Regexp:          `^[-\w]+$`,
			ValidationError: G("Please enter a name consisting only of the characters A-Z, a-z, 0-9 and '-'")},
			"Name", G("Name"), G("The name as it should appear in the URL."))
	}
	if !newNode {
		formData.Name = c.Node.Name()
	}

	fileFields := make([]string, 0)
	nodeFields := nodeType.Fields
	if !newNode {
		nodeFields = append(nodeFields, c.Node.LocalFields...)
	}
	for _, field := range nodeFields {
		formData.Node.GetField(field.Id).ToFormField(form, formData.Fields,
			field, c.UserSession.Locale)
		if field.Type == "File" {
			fileFields = append(fileFields, field.Id)
		}
	}

	switch c.Req.Method {
	case "GET":
	case "POST":
		if len(c.Req.FormValue("New")) == 0 && form.Fill(c.Req.Form) {
			node := formData.Node
			node.Type = nodeType
			pathPrefix := node.GetPathPrefix()
			oldPath := c.Node.Path
			parentPath := c.Node.GetParentPath()
			if newNode {
				parentPath = c.Node.Path
			}
			node.Path = path.Join(parentPath, pathPrefix, formData.Name)
			renamed := !newNode && c.Node.Name() != "" && oldPath != node.Path
			writeNode := true
			if newNode || renamed {
				existing, err := c.Serv.Monsti().GetNode(c.Site.Name, node.Path)
				if err != nil {
					return fmt.Errorf("Could not fetch possibly existing node: %v", err)
				}
				if existing != nil {
					form.AddError("Name", G("A node with this name does already exist"))
					writeNode = false
				}
				if err = node.InitFields(c.Serv.Monsti(), c.Site.Name); err != nil {
					return fmt.Errorf("Could not init node fields: %v", err)
				}
			}
			if writeNode {
				if renamed {
					err := c.Serv.Monsti().RenameNode(c.Site.Name, c.Node.Path, node.Path)
					if err != nil {
						return fmt.Errorf("Could not move node: ", err)
					}
				}
				for _, field := range nodeFields {
					node.GetField(field.Id).FromFormField(formData.Fields, field)
				}
				err := c.Serv.Monsti().WriteNode(c.Site.Name, node.Path, &node)
				if err != nil {
					return fmt.Errorf("Could not update node: ", err)
				}

				if len(fileFields) > 0 && c.Req.MultipartForm != nil {
					for _, name := range fileFields {
						file, _, err := c.Req.FormFile("Fields." + name)
						if err == nil {
							content, err := ioutil.ReadAll(file)
							if err != nil {
								return fmt.Errorf("Could not read multipart file: %v", err)
							}
							if err = c.Serv.Monsti().WriteNodeData(c.Site.Name, node.Path,
								"__file_"+name, content); err != nil {
								return fmt.Errorf("Could not save file: %v", err)
							}
						}
					}
				}
				http.Redirect(c.Res, c.Req, node.Path+"/", http.StatusSeeOther)
				return nil
			}
		}
	default:
		return fmt.Errorf("Request method not supported: %v", c.Req.Method)
	}
	rendered, err := h.Renderer.Render("edit",
		mtemplate.Context{"Form": form.RenderData()},
		c.UserSession.Locale, h.Settings.Monsti.GetSiteTemplatesPath(c.Site.Name))

	if err != nil {
		return fmt.Errorf("Could not render template: %v", err)
	}

	content := []byte(renderInMaster(h.Renderer, []byte(rendered), env, h.Settings,
		*c.Site, c.UserSession.Locale, c.Serv))

	err = c.Session.Save(c.Req, c.Res)
	if err != nil {
		return fmt.Errorf("Could not save user session: %v", err)
	}
	c.Res.Write(content)
	return nil
}