Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
826e5f5
Merge pull request #421 from sinfo/staging
PMax5 Nov 28, 2023
8211828
Merge pull request #426 from sinfo/staging
PMax5 Mar 28, 2024
ec4d673
Merge pull request #430 from sinfo/staging
PMax5 Apr 10, 2024
2ccf05c
Merge pull request #431 from sinfo/staging
andreromao May 29, 2024
79e0172
Merge pull request #433 from sinfo/staging
nalves599 Jan 29, 2025
0aec191
chore: update packages
luckspt Jun 18, 2025
3efefeb
fix: use TabBarThemeData instead of TabBarTheme
luckspt Jun 18, 2025
0e58bc9
chore: create .env.example
luckspt Jun 18, 2025
4259f83
chore: vendor stuff
luckspt Aug 12, 2025
fd2c2d9
chore: open mongodb port to be used in mongodb compass
luckspt Aug 12, 2025
fc5be9d
chore: update go dependencies
luckspt Aug 12, 2025
06c5105
feat: use .env
luckspt Aug 12, 2025
3908043
feat: generate jwt from google jwt (validate locally)
luckspt Aug 12, 2025
e9d91db
chore: whatever flutter lldb stuff this is
luckspt Aug 12, 2025
114529b
chore: company rep and threads prefilled
luckspt Aug 12, 2025
dd8396a
feat: user responsibilities
luckspt Aug 12, 2025
4f5bb28
chore(speaker): update company name & contact object on dto
luckspt Aug 15, 2025
09e5ffb
chore(company): rename
luckspt Aug 15, 2025
f5ae4b3
chore: communications mapped by event
luckspt Aug 15, 2025
8790583
feat: speaker communications
luckspt Aug 15, 2025
8540d79
chore: create readme for frontend
luckspt Aug 15, 2025
f0a7f13
fix: null date instead of default 0001-01-01
luckspt Aug 15, 2025
a4f1be9
fix: null confirmed
luckspt Aug 15, 2025
d72c387
fix: empty date
luckspt Aug 15, 2025
93a6214
chore: enable spaces again
luckspt Aug 15, 2025
3e21af7
feat: companyName and contact on create speaker
luckspt Aug 15, 2025
aaa26b2
chore: send team on jwt
luckspt Aug 17, 2025
74330c4
feat: contact gender and language
luckspt Aug 17, 2025
c81b6c4
feat: contact object on member
luckspt Aug 17, 2025
78cd373
feat: omit post updated when empty
luckspt Aug 17, 2025
67a36f6
feat: update employers order
luckspt Aug 17, 2025
da684a2
Merge branch 'staging' into luckspt/dev
luckspt Aug 19, 2025
69ee636
chore: delete package lock
luckspt Aug 19, 2025
f5f9307
chore: create package lock
luckspt Aug 19, 2025
4883d7c
Merge branch 'staging' into luckspt/dev
luckspt Aug 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
447 changes: 435 additions & 12 deletions backend/go.mod

Large diffs are not rendered by default.

1,665 changes: 1,665 additions & 0 deletions backend/go.sum

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions backend/src/auth/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Claims struct {
ID primitive.ObjectID `json:"id"`
SINFOID string `json:"sinfoid"`
Role models.TeamRole `json:"role"`
Team string `json:"team"`
jwt.StandardClaims
}

Expand All @@ -35,6 +36,7 @@ func SignJWT(credentials models.AuthorizationCredentials) (*string, error) {
ID: credentials.ID,
SINFOID: credentials.SINFOID,
Role: credentials.Role,
Team: credentials.Team,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expirationTime.Unix(),
},
Expand Down Expand Up @@ -75,6 +77,7 @@ func ParseJWT(tokenString string) (*models.AuthorizationCredentials, error) {
ID: claims.ID,
SINFOID: claims.SINFOID,
Role: claims.Role,
Team: claims.Team,
}

return &result, nil
Expand Down
19 changes: 9 additions & 10 deletions backend/src/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"log"

"github.com/joho/godotenv"
"github.com/spf13/viper"
)

Expand Down Expand Up @@ -33,6 +34,7 @@ var (

// Max size of the images to be uploaded by deck2 (Companies public and private images,
// speakers public and private images, etc)
// Also don't forget to update the frontend if this changes
// 10 MB
ImageMaxSize int64 = 10 << 20
MinuteMaxSize int64 = 500 << 10
Expand All @@ -49,6 +51,7 @@ const (
keyPort string = "PORT"

keyDatabaseURI string = "DB_URL"
deckDbURL string = "DECK_DB_URL"
keyDatabaseName string = "DB_NAME"
keyCallbackURL string = "CALLBACK_URL"

Expand Down Expand Up @@ -77,7 +80,6 @@ func set(variable *string, key string, mandatory bool) {
}

func InitializeConfig(filename *string) {

var file = true
if filename == nil {
file = false
Expand All @@ -86,17 +88,14 @@ func InitializeConfig(filename *string) {
}

if file {
viper.SetConfigName(*filename)
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
file = false
}

} else {
viper.SetEnvPrefix(keyPrefix)
viper.AutomaticEnv()
if err := godotenv.Load(*filename); err != nil {
fmt.Printf("Error loading .env file: %v\n", err)
}
}

viper.SetEnvPrefix(keyPrefix)
viper.AutomaticEnv()

set(&Host, keyHost, false)
set(&Port, keyPort, false)

Expand Down
19 changes: 19 additions & 0 deletions backend/src/google/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import (
"net/http"

"github.com/sinfo/deck2/src/auth"
"github.com/sinfo/deck2/src/config"

"google.golang.org/api/idtoken"
)

const oauthGoogleURLAPI = "https://www.googleapis.com/oauth2/v2/userinfo?access_token="
Expand Down Expand Up @@ -73,3 +76,19 @@ func GetUserDataWithToken(token string) (*UserData, error) {

return &result, nil
}


func GetUserDataFromGoogleJWT(token string) (*UserData, error) {
payload, err := idtoken.Validate(context.Background(), token, config.GoogleOAuthClientID)
if err != nil {
return nil, fmt.Errorf("failed to validate ID token: %s", err.Error())
}

return &UserData{
ID: payload.Subject,
Email: payload.Claims["email"].(string),
Verified: payload.Claims["email_verified"].(bool),
Picture: payload.Claims["picture"].(string),
HD: payload.Claims["hd"].(string),
}, nil
}
14 changes: 13 additions & 1 deletion backend/src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ import (
func main() {

prod := flag.Bool("production", false, "Switch between production mode and dev mode")
file := flag.String("config", "", "Config filename. If ommited, configuration is obtained via env vars")
file := flag.String("config", ".env", "Config filename. If ommited, configuration is obtained via env vars")
flag.Parse()

print("Deck2 Backend\n")

// Initialize configuration
print("Initializing configuration...\n")
config.InitializeConfig(file)

if *prod {
Expand All @@ -29,13 +33,21 @@ func main() {
config.Production = true
}

print("Initializing OAuth2\n")
if err := auth.InitializeOAuth2(); err != nil {
log.Fatal(err.Error())
}

print("Initializing JWT\n")
auth.InitializeJWT()

print("Initializing MongoDB\n")
mongodb.InitializeDatabase()

print("Initializing Spaces\n")
spaces.InitializeSpaces()

print("Initializing Router\n")
router.InitializeRouter()

log.Printf("Serving at %s:%s\n", config.Host, config.Port)
Expand Down
2 changes: 1 addition & 1 deletion backend/src/models/company.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type CompanyParticipation struct {
// Participation's billing is a billing _id (see models.Billing).
Billing *primitive.ObjectID `json:"billing" bson:"billing"`

Confirmed time.Time `json:"confirmed" bson:"confirmed"`
Confirmed *time.Time `json:"confirmed,omitempty" bson:"confirmed,omitempty"`

// Is this company participating as a partner.
Partner bool `json:"partner" bson:"partner"`
Expand Down
9 changes: 9 additions & 0 deletions backend/src/models/companyRep.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,12 @@ type CompanyRep struct {
// Contact is a Contact _id (see models.Contact).
Contact primitive.ObjectID `json:"contact" bson:"contact"`
}

type CompanyRepWithContact struct {
// CompanyRep's ID (_id of mongodb).
ID primitive.ObjectID `json:"id" bson:"_id"`
Name string `json:"name" bson:"name"`

// Contact is the contact information of the representative.
Contact *Contact `json:"contact" bson:"contact"`
}
15 changes: 15 additions & 0 deletions backend/src/models/contact.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,27 @@ type ContactMail struct {
Valid bool `json:"valid" bson:"valid"`
}

type Gender string
const (
GenMale Gender = "MALE"
GenFemale Gender = "FEMALE"
GenOther Gender = "OTHER"
)

type Language string
const (
LangEnglish Language = "ENGLISH"
LangPortuguese Language = "PORTUGUESE"
)

// Contact stores contacts' information. It doesn't hold a name, because it's used on models.CompanyRep,
// models.Member and models.Speaker. All of them already hold a name.
type Contact struct {
// Contact's ID (_id of mongodb).
ID primitive.ObjectID `json:"id" bson:"_id"`

Gender Gender `json:"gender" bson:"gender"`
Language Language `json:"language" bson:"language"`
Phones []ContactPhone `json:"phones" bson:"phones"`
Socials ContactSocials `json:"socials" bson:"socials"`
Mails []ContactMail `json:"mails" bson:"mails"`
Expand Down
3 changes: 3 additions & 0 deletions backend/src/models/member.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Member struct {

// Contact is an _id of Contact (see models.Contact).
Contact primitive.ObjectID `json:"contact" bson:"contact"`
ContactObject *Contact `json:"contactObject,omitempty" bson:"-"`
}

// MemberPublic is the public information about a member
Expand All @@ -47,6 +48,8 @@ type AuthorizationCredentials struct {

// Role on SINFO
Role TeamRole

Team string
}

type MemberEventTeam struct {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/models/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ type Post struct {
Text string `json:"text" bson:"text"`

Posted time.Time `json:"posted" bson:"posted"`
Updated time.Time `json:"updated" bson:"updated"`
Updated *time.Time `json:"updated,omitempty" bson:"updated,omitempty"`
}
5 changes: 3 additions & 2 deletions backend/src/models/speaker.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,16 @@ type Speaker struct {

// Contact is an _id of Contact (see models.Contact).
Contact *primitive.ObjectID `json:"contact,omitempty" bson:"contact"`
ContactObject *Contact `json:"contactObject,omitempty" bson:"contactObject"`

// Title of the speaker (CEO @ HugeCorportation, for example).
Title string `json:"title" bson:"title"`

// Bio of the speaker. Careful, this will be visible on our website!
Bio string `json:"bio" bson:"bio"`

// Company name
CompanyName string `json:"companyName" bson:"companyName"`
// Company name
CompanyName string `json:"companyName" bson:"companyName"`

// This is only visible by the team. Praise and trash talk at will.
Notes string `json:"notes" bson:"notes"`
Expand Down
27 changes: 27 additions & 0 deletions backend/src/models/thread.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,30 @@ type Thread struct {
// PENDING => thread is posted and is waiting for the coordination's approval/review.
Status ThreadStatus `json:"status" bson:"status"`
}

type ThreadWithEntry struct {
// Thread's ID (_id of mongodb).
ID primitive.ObjectID `json:"id" bson:"_id"`

// Time posted
Posted time.Time `json:"posted" bson:"posted"`

// Entry is an _id of Post (see models.Post).
Entry *Post `json:"entry" bson:"entry"`

// Meeting is an _id of Meeting (see models.Meeting).
Meeting *primitive.ObjectID `json:"meeting,omitempty" bson:"meeting,omitempty"`

// Comments is an array of _id of Post (see models.Post).
Comments []primitive.ObjectID `json:"comments" bson:"comments"`

// Kind of thread can be "TO", "FROM", "PHONE_CALL", "MEETING".
// This represents the type of communication made with a certain Company/Speaker.
Kind ThreadKind `json:"kind" bson:"kind"`

// Status of this thread can be "APPROVED", "REVIEWED", "PENDING".
// APPROVED => thread is posted and approved by the coordination.
// REVIEWED => thread is posted, but some changed must be made before it's ready to be approved.
// PENDING => thread is posted and is waiting for the coordination's approval/review.
Status ThreadStatus `json:"status" bson:"status"`
}
57 changes: 55 additions & 2 deletions backend/src/mongodb/company.go
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,8 @@ func (ucpd *UpdateCompanyParticipationData) ParseBody(body io.Reader) error {
}

if ucpd.Confirmed == nil {
return errors.New("invalid confirmation date")
// Confirmed may be null
// return errors.New("invalid confirmation date")
}

if ucpd.Notes == nil {
Expand Down Expand Up @@ -735,11 +736,14 @@ func (c *CompaniesType) UpdateCompanyParticipation(companyID primitive.ObjectID,
"$set": bson.M{
"participations.$.member": *data.Member,
"participations.$.partner": *data.Partner,
"participations.$.confirmed": data.Confirmed.UTC(),
"participations.$.notes": *data.Notes,
},
}

if data.Confirmed != nil {
updateQuery["participations.$.confirmed"] = data.Confirmed.UTC()
}

var filterQuery = bson.M{"_id": companyID, "participations.event": currentEvent.ID}

var optionsQuery = options.FindOneAndUpdate()
Expand Down Expand Up @@ -1029,6 +1033,55 @@ func (c *CompaniesType) RemoveEmployer(companyID primitive.ObjectID, companyRep
return &updatedCompany, nil
}

// UpdateEmployersOrderData is the structure used to update a company's employers order
type UpdateEmployersOrderData struct {
Employers *[]primitive.ObjectID `json:"employers"`
}

// ParseBody fills the UpdateEmployersOrderData from a body
func (ueod *UpdateEmployersOrderData) ParseBody(body io.Reader) error {
if err := json.NewDecoder(body).Decode(ueod); err != nil {
return err
}

if ueod.Employers == nil {
return errors.New("invalid employers")
}

// Validate that all employer IDs exist
for _, employerID := range *ueod.Employers {
if _, err := CompanyReps.GetCompanyRep(employerID); err != nil {
return errors.New("invalid employer ID: " + employerID.Hex())
}
}

return nil
}

// UpdateEmployersOrder updates the order of employers for a company
func (c *CompaniesType) UpdateEmployersOrder(companyID primitive.ObjectID, data UpdateEmployersOrderData) (*models.Company, error) {
ctx := context.Background()
var updatedCompany models.Company

var updateQuery = bson.M{
"$set": bson.M{
"employers": data.Employers,
},
}

var filterQuery = bson.M{"_id": companyID}

var optionsQuery = options.FindOneAndUpdate()
optionsQuery.SetReturnDocument(options.After)

if err := c.Collection.FindOneAndUpdate(ctx, filterQuery, updateQuery, optionsQuery).Decode(&updatedCompany); err != nil {
log.Println("Error updating employers order:", err)
return nil, err
}

return &updatedCompany, nil
}

// AddThread adds a models.Thread to a company's participation's list of communications (related to the current event).
func (c *CompaniesType) AddThread(companyID primitive.ObjectID, threadID primitive.ObjectID) (*models.Company, error) {

Expand Down
6 changes: 6 additions & 0 deletions backend/src/mongodb/contact.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type GetContactsOptions struct {

// CreateContactData contains data needed to create a contact
type CreateContactData struct {
Gender models.Gender `json:"gender" bson:"gender"`
Language models.Language `json:"language" bson:"language"`
Phones []models.ContactPhone `json:"phones" bson:"phones"`
Socials models.ContactSocials `json:"socials" bson:"socials"`
Mails []models.ContactMail `json:"mails" bson:"mails"`
Expand Down Expand Up @@ -127,6 +129,8 @@ func (c *ContactsType) CreateContact(data CreateContactData) (*models.Contact, e
insertData["phones"] = data.Phones
insertData["socials"] = data.Socials
insertData["mails"] = data.Mails
insertData["gender"] = data.Gender
insertData["language"] = data.Language

insertResult, err := c.Collection.InsertOne(ctx, insertData)
if err != nil {
Expand All @@ -149,6 +153,8 @@ func (c *ContactsType) UpdateContact(contactID primitive.ObjectID, data CreateCo
"phones": data.Phones,
"socials": data.Socials,
"mails": data.Mails,
"gender": data.Gender,
"language": data.Language,
},
}

Expand Down
Loading