beego is an open-source, high-performance web framework for the Go programming language.

Beego Build Status GoDoc Foundation Go Report Card

Beego is used for rapid development of enterprise application in Go, including RESTful APIs, web apps and backend services.

It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding.

architecture

Beego is compos of four parts:

  1. Base modules: including log module, config module, governor module;
  2. Task: is used for running timed tasks or periodic tasks;
  3. Client: including ORM module, httplib module, cache module;
  4. Server: including web module. We will support gRPC in the future;

Please use RELEASE version, or master branch which contains the latest bug fix

Quick Start

Official website

Example

If you could not open official website, go to beedoc

Web Application

Http Request

Create hello directory, cd hello directory

mkdir hello
cd hello

Init module

go mod init

Download and install

go get github.com/beego/beego/v2@latest

Create file hello.go

package main

import "github.com/beego/beego/v2/server/web"

func main() {
	web.Run()
}

Build and run

go build hello.go
./hello

Go to http://localhost:8080

Congratulations! You've just built your first beego app.

Features

Modules

Community

License

beego source code is licensed under the Apache Licence, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html).

Comments
  • Automatic Parameter Router

    Automatic Parameter Router

    This is a POC for a feature i've been working on that I'd like to get reviewed before I complete the work (to make sure the direction is ok) The idea is to make Comments Controller even more "magical" by translating request parameters to method parameters.

    [See updated information below]

    Let me know if the direction looks ok and I will complete the missing parts. Also if you think this is good, please review the changes. Note that most changes are in new files and there should be no changes to current flows. Changes in existing files are minimal.

  • Security Concerns: Generating Random Bytes

    Security Concerns: Generating Random Bytes

    Hi,

    I couldn't see any existing issues on this (I also can't read Chinese) so apologies if they have been pointed out. Stemmed from a Reddit discussion I was curious about beego's API and took a look at the source and discovered these potential flaws.

    First up: your session IDs are not securely generated and may be predictable

    • In session.go you use a combination of crypto/rand, time.Unix and a SHA-1 hash to generate a session ID. You should just use crypto/rand and base32 encode it as per gorilla/sessions, as otherwise you are introducing predictability into your session ID generation.
    • Your XSRF tokens, by default, expire in 60s. From a usability perspective this isn't a sane default: if a user takes > 60s to fill out a form or submit something, they'll error. There's no need for such an aggressive default.
    • Your XSRF tokens are only 15 bytes long, but your session IDs are 24 bytes long. Why the difference? I suggest following gorilla/sessions, Django & Rails' lead here and reading 32 bytes out (for all short-lived secure tokens). Share a GenerateRandomBytes(n int) function throughout your application rather than inventing the wheel, which leads me to...
    • RandomCreateBytes here may end up truncating the generated string, making it less secure. Just base32 encode it. Look at securecookie's GenerateRandomKey() function. I'd suggest returning []byte, err instead of return nil on an error though, as otherwise you need to manually check for nil (for safety). Better to just return an explicit error.

    I have not been through the source in full, but these issues were the most glaring and I recommend resolving them ASAP. I also recommend instructing users on how to generate secure, persistent XSRF session keys and session cookie keys using either crypto/rand to save to file (I'd suggest using a CLI flag to allow this to be done as a once off, and using log.Fatal if no keys are present) or the OpenSSL CLI to do the same.

  • When i run bee command. the error encountered:

    When i run bee command. the error encountered: "dyld: attempt to run simulator program outside simulator (DYLD_ROOT_PATH not set)"

    Please answer these questions before submitting your issue. Thanks!

    1. What version of Go and beego are you using (bee version)? go version go1.14.6 darwin/amd64

    2. What operating system and processor architecture are you using (go env)? mac os catalina 10.15.4 ,6-Core Intel Core i7 go env: image

    3. What did you do? I installed the Go from pkg below image and then i used the command below to set the proxy:

    go env -w GO111MODULE=on
    go env -w GOPROXY=https://goproxy.io,direct
    

    and then I used the command below to install the beego and bee:

    go get -u github.com/astaxie/beego
    go get -u github.com/beego/bee
    

    so far so good.

    1. What did you expect to see? I want to use the bee new *** to create a project.

    2. What did you see instead? when I ran the command "bee" or "bee new ***", i encountered the error below: image

    I reboot the mac, uninstall go and re-install go and bee for 3 times, it doesn't work. can someone help me? thanks.

  • 用SaveToFile文件上传后,一直占着虚拟内存没有释放

    用SaveToFile文件上传后,一直占着虚拟内存没有释放

    发现在windows中用SaveToFile保存上传后的文件,一直占着虚拟内存没有释放,再上传多几次C盘就满了 有什么方法比较优化的呢? 代码如下:

    package main
    
    import (
        "github.com/astaxie/beego"
    )
    
    type UploadController struct {
        beego.Controller
    }
    func (this *UploadController) Post() {
        _, h, _ := this.GetFile("uploadfile")
        this.SaveToFile("uploadfile", "./static/files/"+h.Filename)
        this.Ctx.Redirect(302, "/upload")
    
    }
    
    func main() {
        beego.Router("/upload", &UploadController{})
        beego.Run()
    }
    
  • Module latest found, but does not contain package beego/server/web

    Module latest found, but does not contain package beego/server/web

    Please answer these questions before submitting your issue. Thanks!

    1. What version of Go and beego are you using (bee version)? Go version : go1.15.4 Bee version: v1.12.0
    2. What operating system and processor architecture are you using (go env)?
    GOARCH="amd64"
    GOBIN=""
    GOCACHE="/Users/theo/Library/Caches/go-build"
    GOENV="/Users/theo/Library/Application Support/go/env"
    GOEXE=""
    GOFLAGS=""
    GOHOSTARCH="amd64"
    GOHOSTOS="darwin"
    GOINSECURE=""
    GOMODCACHE="/Users/theo/go/pkg/mod"
    GONOPROXY=""
    GONOSUMDB=""
    GOOS="darwin"
    GOPATH="/Users/theo/go"
    GOPRIVATE=""
    GOPROXY="https://proxy.golang.org,direct"
    GOROOT="/usr/local/Cellar/go/1.15.4/libexec"
    GOSUMDB="sum.golang.org"
    GOTMPDIR=""
    GOTOOLDIR="/usr/local/Cellar/go/1.15.4/libexec/pkg/tool/darwin_amd64"
    GCCGO="gccgo"
    AR="ar"
    CC="clang"
    CXX="clang++"
    CGO_ENABLED="1"
    GOMOD="/dev/null"
    CGO_CFLAGS="-g -O2"
    CGO_CPPFLAGS=""
    CGO_CXXFLAGS="-g -O2"
    CGO_FFLAGS="-g -O2"
    CGO_LDFLAGS="-g -O2"
    PKG_CONFIG="pkg-config"
    GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/zl/4vn0pm8x4lz1h2bm6y5kkdnm0000gn/T/go-build854159209=/tmp/go-build -gno-record-gcc-switches -fno-common"
    
    1. What did you do?

    I created a new installation of Beego using the bee api my-api command and then I add this code into controllers/object.go:

    package controllers
    
    import (
    	"my-app/models"
    	"encoding/json"
    
    	beego "github.com/astaxie/beego/server/web"
    )
    
    // Operations about object
    type ObjectController struct {
    	beego.Controller
    }
    
    1. What did you expect to see? I am expecting to see the messages Built successfully and app is running

    2. What did you see instead?

    2020/11/11 15:33:47 INFO     ▶ 0002 Initializing watcher...
    go: finding module for package github.com/astaxie/beego/server/web
    controllers/object.go:7:2: module github.com/astaxie/beego@latest found (v1.12.3), but does not contain package github.com/astaxie/beego/server/web
    2020/11/11 15:33:49 ERROR    ▶ 0003 Failed to build the application: go: finding module for package github.com/astaxie/beego/server/web
    controllers/object.go:7:2: module github.com/astaxie/beego@latest found (v1.12.3), but does not contain package github.com/astaxie/beego/server/web
    
  • beego 时区问题

    beego 时区问题

    用的是最新的 linux: [root@li538-145]# date Fri Jan 3 12:00:56 CST 2014

    mysql: mysql> select now(); +---------------------+ | now() | +---------------------+ | 2014-01-03 12:01:13 | +---------------------+ 1 row in set (0.00 sec)

    如果程序中 不设置orm.DefaultTimeLoc = time.UTC 则慢8小时 但是获取的时间是对的 now := time.Now() fmt.Println(now) fmt.Println(now.Location()) fmt.Println(now.Zone())

    2014-01-03 12:03:50.31161402 +0800 CST Local CST 28800

    设置的话慢16小时

  • c.Ctx.Input.RequestBody empty value

    c.Ctx.Input.RequestBody empty value

    this is happen after I update beego to 1.6.1.

    this is my code func (c *AuthController) Login() {

        var data models.User
        if err := json.Unmarshal(c.Ctx.Input.RequestBody, &data); err != nil {
            c.Ctx.Output.SetStatus(400)
            fmt.Println(c.Ctx.Input.RequestBody)
            c.Ctx.Output.Body([]byte("empty title"))
            return
        }
        res := struct{  
            Data []*models.User 
        }{}
    
        var cond *orm.Condition
        cond = orm.NewCondition()
    
        cond = cond.And("username", data.Username)
        cond = cond.And("password", data.Password)
        lim :=1
    
        var qs orm.QuerySeter
        qs = orm.NewOrm().QueryTable("user").SetCond(cond).Limit(lim)
        _,err := qs.All(&res.Data)
        if err != nil {
            c.Ctx.Output.SetStatus(400)
            c.Ctx.Output.Body([]byte(err.Error()))
            return
        }
        result := struct{   
            Success bool
            Message string
        }{} 
    }
    

    curl -X POST http://lo0/login -d '{"username" : "admin", "password":"admin"}' empty title

    lmvm@lm17 ~/go/src/github.com/goldalworming/auth $ go run main.go [] <----fmt.Println return this empty array

  • Beego ORM模块建议

    Beego ORM模块建议

    例如,我有如下代码:

    var hotCourse []models.VCourse sql = "SELECT * FROM v_course ORDER BY hits DESC LIMIT 4" o.Raw(sql).QueryRows(&hotCourse)

    传入的hotCourse对应的models.VCourse里面的字段与数据库里面的字段顺序要一致才能将预期的字段值设置到VCourse的字段里面去。

    如: type VCourse struct{ Id int64 Name string }

    那么sql语句里面必须SELECT id,name FROM table才能将字段的值绑定上去。这很不方便。

    我希望是这样的: 当我的结构体只有两个字段:Id与Name,那么,在结果绑定到结构体上的时候,先遍历结构体的字段,按照Model的定义(即与表字段之间的定义)进行查找SQL里面的字段,然后将该字段的值绑定到结构体的对应字段上。这样就很完善了。

    在编写代码的时候,就不用再担心字段顺序的问题了。也不用担心,结构体的字段只有2个,而SQL字段有3个,导致匹配不上而报错了。

    能否请设计ORM的大神改善一下原生SQL语句的智能能力呢。谢谢!

  • Cors problems

    Cors problems

    I have a problem with cors and beego. This is my code:

    func main(){
    beego.InsertFilter("*", beego.BeforeRouter,cors.Allow(&cors.Options{
            AllowAllOrigins: true,
            AllowMethods: []string{"GET", "DELETE", "PUT", "PATCH", "OPTIONS"},
            AllowHeaders: []string{"Origin", "Access-Control-Allow-Origin"},
            ExposeHeaders: []string{"Content-Length", "Access-Control-Allow-Origin"},
            AllowCredentials: true,
        }))
    beego.Run()
    }
    

    I receive this answer: "XMLHttpRequest cannot load http://localhost:8080/. No 'Access-Control-Allow-Origin' header is present on the requested resource"

    I can't figure it out. Do you have any ideas? Thanks for any help.

  • 注解路由未生成?

    注解路由未生成?

    runmode已经设置成了dev,注解也写了,但是未生成commentsRouter.go文件 OS win 10,beego版本 master版本

    runmode = "dev"
    

    router.go

    func init() {
    	ns := beego.NewNamespace("/admin",
    
    		beego.NSNamespace("/contents",
    			beego.NSInclude(
    				&controllers.ContentController{},
    			),
    		),
    	)
    	beego.AddNamespace(ns)
    }
    

    controllers/content.go

    type ContentController struct {
    	BaseController
    }
    
    // @router / [get]
    func (this *ContentController) GetContents() {
    	defer this.ServeJSON()
            // .....
    }
    
  • Support get environment variables in config

    Support get environment variables in config

    get environment variable if config item has prefix $ENV_ $$env ${env}. if environment variable is empty or not exist then return default value (split with ||). e.g.

    token = ${TOKEN||astaxie}
    [demo]
    password = ${MyPWD}
    user = ${MyUser||beego}
    

    the result of config.String("demo::password") is the $MyPWD environment variable. some people need it , such as #1283 .

  • beego orm how to  insert on duplicate key update in batch

    beego orm how to insert on duplicate key update in batch

    beego v2.0.7 go 1.8

    we have 100 thousand records want to insert data use insert on duplicate key update in batch but beego only support InsertOrUpdate/InsertOrUpdateWithCtx to insert one record to database

      ```
      InsertOrUpdate(md interface{}, colConflitAndArgs ...string) (int64, error)
      InsertOrUpdateWithCtx(ctx context.Context, md interface{}, colConflitAndArgs ...string) (int64, error)
      ```
    

    how can I batch insert like insert on duplicate key update in batch

  • v1 beego NewNamespace throws errors on Manjaro Linux

    v1 beego NewNamespace throws errors on Manjaro Linux

    1. What version of Go and beego are you using (bee version)? Golang 1.18.1, beego v1.12.11

    2. What operating system and processor architecture are you using (go env)? Manjaro Linux latest(rolling)

    3. What did you do? Running the following code(figure 1) would cause errors as follows. image

    casdoor-casdoor-1 exited with code 2
    casdoor-casdoor-1 | panic: prefix should has path
    casdoor-casdoor-1 |
    casdoor-casdoor-1 | goroutine 1 [running]:
    casdoor-casdoor-1 | github.com/beego/beego.(*Tree).addtree(0x0, {0x2b42ae0, 0x174ef40, 0xc000a0e4e8}, 0x1, {0x0, 0x0, 0xc000a0e018}, {0x0, 0x0})
    casdoor-casdoor-1 | /go/src/casdoor/vendor/github.com/beego/beego/tree.go:58 +0x1185
    casdoor-casdoor-1 | github.com/beego/beego.(*Tree).AddTree(0x174ef40, {0x0, 0xc000040430}, 0x3)
    casdoor-casdoor-1 | /go/src/casdoor/vendor/github.com/beego/beego/tree.go:53 +0x54
    casdoor-casdoor-1 | github.com/beego/beego.(*Namespace).Namespace(0xc0000ae828, {0xc00035b278, 0x1, 0x1})
    casdoor-casdoor-1 | /go/src/casdoor/vendor/github.com/beego/beego/namespace.go:212 +0x205
    casdoor-casdoor-1 | github.com/beego/beego.NSNamespace.func1(0x30)
    casdoor-casdoor-1 | /go/src/casdoor/vendor/github.com/beego/beego/namespace.go:387 +0x5a
    casdoor-casdoor-1 | github.com/beego/beego.NewNamespace({0x19eb591, 0x1}, {0xc00035bce0, 0x2, 0x1})
    casdoor-casdoor-1 | /go/src/casdoor/vendor/github.com/beego/beego/namespace.go:42 +0x104
    casdoor-casdoor-1 | github.com/casdoor/casdoor/routers.initAPI()
    casdoor-casdoor-1 | /go/src/casdoor/routers/router.go:33 +0x1a7
    casdoor-casdoor-1 | github.com/casdoor/casdoor/routers.init.1()
    casdoor-casdoor-1 | /go/src/casdoor/routers/router.go:29 +0x17
    
    1. What did you expect to see?

    No error.

    1. What did you see instead?

    Errors as shown above.

    We suspect that it might be compatibility of Manjaro Linux latest(rolling) and beego

  • Access to registered models

    Access to registered models

    1. What version of Go and beego are you using (bee version)? 2.0.5

    2. What operating system and processor architecture are you using (go env)? Windows, amd64

    3. What did you expect to see? An exported method or function to view all the registered models in the ORM.

    4. What did you see instead? The unexported modelcache struct.

    Not mreally an issue, but a question. I want a simple way to create an admin site for my project. The best way to go about this in my opinion is to get all registered models from the ORM, and work off those models registered. Maybe there is a better way, in which case I'm more than glad to hear those options. There is no method documented which I could find to accomplish this.

    To be more specific, I'm looking for a way to access one of the following methods defined on modelCache

    // get all model info
    func (mc *modelCache) all() map[string]*modelInfo {
    	m := make(map[string]*modelInfo, len(mc.cache))
    	for k, v := range mc.cache {
    		m[k] = v
    	}
    	return m
    }
    
    // get ordered model info
    func (mc *modelCache) allOrdered() []*modelInfo {
    	m := make([]*modelInfo, 0, len(mc.orders))
    	for _, table := range mc.orders {
    		m = append(m, mc.cache[table])
    	}
    	return m
    }
    

    Going with that, the following fields would also be very nice if they were exported:

    // single model info
    type modelInfo struct {
    	manual    bool
    	isThrough bool
    	pkg       string
    	name      string // -> Name
    	fullName  string // -> FullName
    	table     string // -> Table
    	model     interface{} // -> Model
    	fields    *fields // -> Fields
    	addrField reflect.Value // store the original struct value
    	uniques   []string
    }
    

    Along with the entire fields struct, and fieldinfo struct. There is so much awesome logic hiding behind the ORM, which I think a lot of people could do great creative things with! Would it be much of a hassle to export some of these methods and fields?

  • embed.FS with Beego

    embed.FS with Beego

    1. What version of Go and beego are you using (bee version)? 2.0.5

    2. What operating system and processor architecture are you using (go env)? Windows, amd64

    3. What did you expect to see? A way to embed templates when building the application

    4. What did you see instead? No clear documentation on this subject.

    Basically, I have a question. Is there a way to embed the HTML files with the executable for distribution? Could a feature like this be implemented by users of beego? I did not see any clear documentation on this subject, but I might have missed it.

  • 【temp file leak】if upload size > 32MB, a tmp file will be leave behind in /tmp directory.

    【temp file leak】if upload size > 32MB, a tmp file will be leave behind in /tmp directory.

    English Only. Please use English because others could join the discussion if they got similar issue!

    Please answer these questions before submitting your issue. Thanks!

    1. What version of Go and beego are you using (bee version)? | ___
      | |/ / ___ ___ | ___ \ / _ \ / _
      | |
      / /| /| / __/ _| ___| v2.0.4

    ├── GoVersion : go1.18 ├── GOOS : windows ├── GOARCH : amd64 ├── NumCPU : 4 ├── GOPATH : C:\Users\dell\go ├── GOROOT : C:\Program Files\Go ├── Compiler : gc └── Date : Saturday, 22 Oct 2022

    1. What operating system and processor architecture are you using (go env)? GOOS=windows GOARCH=amd64

    2. What did you do? I upload some files which bigger than defaultMemSize(32MB)

    3. What did you expect to see? temp file is deleted

    4. What did you see instead? the temp file in /tmp directory will be not deleted. The name of temp file is "multipart-XXXXXXXX"

    5. My Solution by According to this issue(https://github.com/golang/go/issues/20253), after I call c.SaveToFile in controller, I call c.Ctx.Request.MultipartForm.RemoveAll() It works.

    I think beego is better at doing this than users.

letgo is an open-source, high-performance web framework for the Go programming language.

high-performance Lightweight web framework for the Go programming language. golang web framework,高可用golang web框架,go语言 web框架 ,go web

Sep 23, 2022
A Go API project using Beego(Go Framework) with Swagger UI

Beego_API_with_swagger_UI Descriptions This is a Go API project using Beego(Go F

Dec 20, 2021
High performance, minimalist Go web framework
High performance, minimalist Go web framework

Supported Go versions As of version 4.0.0, Echo is available as a Go module. Therefore a Go version capable of understanding /vN suffixed imports is r

Jan 2, 2023
Gearbox :gear: is a web framework written in Go with a focus on high performance
Gearbox :gear: is a web framework written in Go with a focus on high performance

gearbox ⚙️ is a web framework for building micro services written in Go with a focus on high performance. It's built on fasthttp which is up to 10x fa

Jan 3, 2023
hiboot is a high performance web and cli application framework with dependency injection support

Hiboot - web/cli application framework About Hiboot is a cloud native web and cli application framework written in Go. Hiboot is not trying to reinven

Nov 20, 2022
Gearbox :gear: is a web framework written in Go with a focus on high performance
Gearbox :gear: is a web framework written in Go with a focus on high performance

gearbox ⚙️ is a web framework for building micro services written in Go with a focus on high performance. It's built on fasthttp which is up to 10x fa

Dec 29, 2022
High performance, simple Go web framework

Elton Elton的实现参考了koa以及echo,中间件的调整均为洋葱模型:请求由外至内,响应由内至外。主要特性如下: 处理函数(中间件)均以返回error的形式响应出错,方便使用统一的出错处理中间件将出错统一转换为对应的输出(JSON),并根据出错的类型等生成各类统计分析 成功响应数据直接赋值

Dec 17, 2022
Dragon 🐲 🐲 🐲 is an enterprise high performance web framework with Go for the feature and comfortable develop.

Dragon start dragon ab performance Dragon ?? ?? ?? is a lightweight high performance web framework with Go for the feature and comfortable develop. 中文

Sep 14, 2022
Dragon 🐲 🐲 🐲 is a lightweight high performance web framework with Go for the feature and comfortable develop.

Dragon project new link start dragon ab performance Dragon ?? ?? ?? is a lightweight high performance web framework with Go for the feature and comfor

Sep 6, 2022
A high productivity, full-stack web framework for the Go language.

Revel Framework A high productivity, full-stack web framework for the Go language. Current Version: 1.0.0 (2020-07-11) Supports go.mod package managem

Jan 7, 2023
Goal is a toolkit for high productivity web development in Go language in the spirit of Revel Framework that is built around the concept of code generation.

Goal Goal is a set of tools for high productivity web development in Go language. Goal, being mostly inspired by Revel Framework and its discussions,

Sep 27, 2021
GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang.

GoFrame English | 简体中文 GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang. If you're a

Jan 2, 2023
Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.
Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.

Flamingo Framework Flamingo is a web framework based on Go. It is designed to build pluggable and maintainable web projects. It is production ready, f

Jan 5, 2023
Golanger Web Framework is a lightweight framework for writing web applications in Go.

/* Copyright 2013 Golanger.com. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except

Nov 14, 2022
The jin is a simplified version of the gin web framework that can help you quickly understand the core principles of a web framework.

jin About The jin is a simplified version of the gin web framework that can help you quickly understand the core principles of a web framework. If thi

Jul 14, 2022
Go-app is a package to build progressive web apps with Go programming language and WebAssembly.
Go-app is a package to build progressive web apps with Go programming language and WebAssembly.

Go-app is a package to build progressive web apps with Go programming language and WebAssembly.

Dec 30, 2022
Tigo is an HTTP web framework written in Go (Golang).It features a Tornado-like API with better performance. Tigo是一款用Go语言开发的web应用框架,API特性类似于Tornado并且拥有比Tornado更好的性能。
Tigo is an HTTP web framework written in Go (Golang).It features a Tornado-like API with better performance.  Tigo是一款用Go语言开发的web应用框架,API特性类似于Tornado并且拥有比Tornado更好的性能。

Tigo(For English Documentation Click Here) 一个使用Go语言开发的web框架。 相关工具及插件 tiger tiger是一个专门为Tigo框架量身定做的脚手架工具,可以使用tiger新建Tigo项目或者执行其他操作。

Jan 5, 2023
Package macaron is a high productive and modular web framework in Go.
Package macaron is a high productive and modular web framework in Go.

Macaron Package macaron is a high productive and modular web framework in Go. Getting Started The minimum requirement of Go is 1.6. To install Macaron

Jan 2, 2023