~fkfd/sophon

5af6bfa3362ae3ddaa588fedd09553adf3812280 — Frederick Yin 3 years ago 71bc836
Meta is now a section in code
4 files changed, 28 insertions(+), 28 deletions(-)

M history.go
M routes.go
M wiki.go
M wikipage.go
M history.go => history.go +5 -5
@@ 8,7 8,7 @@ import (

type historyEntry struct {
	Action   string
	Part     string
	Section  string
	Time     time.Time
	ClientIP string
	Message  string


@@ 19,7 19,7 @@ func (entry historyEntry) Marshal() string {
	return strings.Join([]string{
		"-----BEGIN ENTRY-----",
		"ACTION: " + entry.Action,
		"PART: " + entry.Part,
		"SECTION: " + entry.Section,
		"TIME: " + entry.Time.Format(time.RFC3339),
		"IP: " + entry.ClientIP,
		"MESSAGE: " + entry.Message,


@@ 57,8 57,8 @@ func parseHistoryFile(page, hist string) (historyChronicle, error) {
				entries = append(entries, ent)
			case strings.HasPrefix(ln, "ACTION: "):
				ent.Action = ln[8:]
			case strings.HasPrefix(ln, "PART: "):
				ent.Part = ln[6:]
			case strings.HasPrefix(ln, "SECTION: "):
				ent.Section= ln[9:]
			case strings.HasPrefix(ln, "TIME: "):
				t, err := time.Parse(time.RFC3339, ln[6:])
				if err != nil {


@@ 105,7 105,7 @@ func (chronicle historyChronicle) GeminiPage() string {
			strings.Join([]string{
				entry.ClientIP,
				entry.Action,
				entry.Part,
				entry.Section,
				"at",
				entry.Time.Format(time.RFC3339),
			}, " "),

M routes.go => routes.go +1 -1
@@ 60,7 60,7 @@ func routeWikiRequest(segs []string, query string, clientIP net.Addr) (string, s
		if len(segs) == 3 || segs[3] == "" {
			if query == "" {
				// /wiki/<page>/edit
				return "10 Specify which part to edit", ""
				return "10 Specify which section to edit", ""
			} else if query == "meta" {
				// /wiki/<page>/edit?meta
				sessionID, err := initEditSession(pageName, "meta", clientIP.String())

M wiki.go => wiki.go +16 -16
@@ 52,7 52,7 @@ func readWikiPage(pageName string) (string, error) {
type editSessionManifest struct {
	Version          string
	PageTitle        string
	Part             string
	Section             string
	ClientIP         string
	LastAccessedTime string
}


@@ 69,7 69,7 @@ func parseManifest(id string) (editSessionManifest, error) {
	}
	manifest.Version = lines[0][7:]
	manifest.PageTitle = lines[2]
	manifest.Part = lines[3]
	manifest.Section = lines[3]
	manifest.ClientIP = lines[4]
	manifest.LastAccessedTime = lines[5]
	return manifest, nil


@@ 80,22 80,22 @@ func (manifest editSessionManifest) String() string {
		"sophon " + manifest.Version,
		"editing page",
		manifest.PageTitle,
		manifest.Part,
		manifest.Section,
		manifest.ClientIP,
		manifest.LastAccessedTime,
	}, "\n")
}

func initEditSession(page, part, clientIP string) (string, error) {
func initEditSession(page, section, clientIP string) (string, error) {
	now := time.Now().Format(time.RFC3339) // 2006-01-02T15:04:05Z07:00
	rand := sha256.Sum256([]byte(page + part + clientIP + now))
	rand := sha256.Sum256([]byte(page + section + clientIP + now))
	id := hex.EncodeToString(rand[:])[:16]
	// mkdir sessions/<id>/
	err := os.Mkdir("sessions/"+id, dirPerm)
	if err != nil {
		return "", err
	}
	manifest := editSessionManifest{sophonVersion, page, part, clientIP, now}.String()
	manifest := editSessionManifest{sophonVersion, page, section, clientIP, now}.String()
	// cp wiki/<page>.gmi sessions/
	pageFile := "sessions/" + id + "/" + page + ".gmi"
	copyFile("wiki/"+page+".gmi", pageFile)


@@ 108,8 108,8 @@ func initEditSession(page, part, clientIP string) (string, error) {
		return "", err
	}

	// extract <part> from <page>
	stageContents, err := extractPartFromArticle(article, part)
	// extract <section> from <page>
	stageContents, err := extractSectionFromArticle(article, section)
	if err != nil {
		return "", err
	}


@@ 176,10 176,10 @@ func previewPage(id string) (string, error) {
		return "", err
	}

	// obtain the title and part of the page the user is editing
	// obtain the title and section of the page the user is editing
	manifest, err := parseManifest(id)
	title := manifest.PageTitle
	part := manifest.Part
	section := manifest.Section
	file, err := ioutil.ReadFile("sessions/" + id + "/" + title + ".gmi")
	if err != nil {
		return "", err


@@ 190,10 190,10 @@ func previewPage(id string) (string, error) {
	}

	// inject STAGE into where it came from in <title>.gmi
	if part == "meta" {
	if section == "meta" {
		article.Meta = stage
	} else {
		indexChain := indexChainOf(part)
		indexChain := indexChainOf(section)
		if len(indexChain) == 1 {
			article.Sections[indexChain[0]].Content = stage
		} else if len(indexChain) == 2 {


@@ 220,9 220,9 @@ func commitSession(id, msg string) error {
		return err
	}
	title := manifest.PageTitle
	part := manifest.Part
	if part != "meta" {
		part = "section " + part
	section := manifest.Section
	if section != "meta" {
		section = "section " + section
	}
	diff, err := ioutil.ReadFile("sessions/" + id + "/" + "DIFF")
	if err != nil {


@@ 248,7 248,7 @@ func commitSession(id, msg string) error {
	}

	// keep history log
	entry := historyEntry{title, part, time.Now(), manifest.ClientIP, msg, string(diff)}
	entry := historyEntry{title, section, time.Now(), manifest.ClientIP, msg, string(diff)}
	histFile, err := os.OpenFile("history/"+title+".hist", os.O_APPEND|os.O_WRONLY|os.O_CREATE, filePerm)
	defer histFile.Close()
	_, err = histFile.WriteString(entry.Marshal())

M wikipage.go => wikipage.go +6 -6
@@ 21,7 21,7 @@ type section struct {
type wikiArticle struct {
	Title    string
	Meta     string
	Sections []section
	Sections []section // body sections
}

func parseWikiPage(page string) (wikiArticle, error) {


@@ 39,7 39,7 @@ func parseWikiPage(page string) (wikiArticle, error) {
	article.Title = lines[0][2:]

	// the first 2nd-level heading is where the ToC starts
	// between the title and that line is the meta part
	// between the title and that line is the meta section
	// and the line above the second 2nd-level heading is where the ToC ends
	// TODO: identify preformatted text blocks
	metaPart := ""


@@ 68,7 68,7 @@ func parseWikiPage(page string) (wikiArticle, error) {
	}
	article.Meta = metaPart

	// parse contents, i.e. sections and subsections
	// parse contents, i.e. body sections and subsections
	var sections []section
	for n := 0; n < len(contentsPart); n++ {
		line := contentsPart[n]


@@ 168,13 168,13 @@ func indexChainOf(sectionNumber string) []int {
	return []int{}
}

func extractPartFromArticle(article wikiArticle, part string) (string, error) {
	if part == "meta" {
func extractSectionFromArticle(article wikiArticle, sectionName string) (string, error) {
	if sectionName == "meta" {
		return article.Meta, nil
	}

	// user wants to edit a section/subsection
	indexChain := indexChainOf(part)
	indexChain := indexChainOf(sectionName)
	if len(indexChain) == 0 {
		return "", errors.New("section number invalid")
	}