@@ -21,6 +21,7 @@ import {
2121 type PostFlagsPublic ,
2222 type Campaign ,
2323 type OrganizationLink ,
24+ SourceType ,
2425} from '../entity' ;
2526import {
2627 OrganizationMemberRole ,
@@ -36,6 +37,7 @@ import {
3637 domainOnly ,
3738 getSmartTitle ,
3839 getTranslationRecord ,
40+ getUserTopReadingTags ,
3941 transformDate ,
4042} from '../common' ;
4143import { GQLComment } from '../schema/comments' ;
@@ -64,6 +66,7 @@ import { OpportunityUserType } from '../entity/opportunities/types';
6466import { OrganizationLinkType } from '../common/schema/organizations' ;
6567import type { GCSBlob } from '../common/schema/userCandidate' ;
6668import { QuestionType } from '../entity/questions/types' ;
69+ import { snotraClient } from '../integrations/snotra' ;
6770
6871const existsByUserAndPost =
6972 ( entity : string , build ?: ( queryBuilder : QueryBuilder ) => QueryBuilder ) =>
@@ -1715,6 +1718,182 @@ const obj = new GraphORM({
17151718 } ,
17161719 } ,
17171720 } ,
1721+ OpportunityPreviewCompany : {
1722+ from : 'UserExperience' ,
1723+ requiredColumns : [ 'userId' , 'verified' , 'type' , 'startedAt' ] ,
1724+ additionalQuery : ( _ , alias , qb ) =>
1725+ qb . leftJoin ( 'company' , 'c' , `c.id = ${ alias } ."companyId"` ) ,
1726+ fields : {
1727+ name : {
1728+ rawSelect : true ,
1729+ select : ( _ , alias ) => `COALESCE(c.name, ${ alias } ."customCompanyName")` ,
1730+ } ,
1731+ favicon : {
1732+ rawSelect : true ,
1733+ select : ( ) => 'NULL' ,
1734+ } ,
1735+ } ,
1736+ } ,
1737+ OpportunityPreviewUser : {
1738+ from : 'User' ,
1739+ requiredColumns : [ 'id' ] ,
1740+ fields : {
1741+ profileImage : {
1742+ select : 'image' ,
1743+ } ,
1744+ anonId : {
1745+ select : ( ) => 'NULL' ,
1746+ transform : ( _ , ctx , parent ) => {
1747+ const user = parent as User ;
1748+ if ( ! user . id ) return null ;
1749+
1750+ // Deterministic hash from userId
1751+ let hash = 0 ;
1752+ for ( let i = 0 ; i < user . id . length ; i ++ ) {
1753+ hash = ( hash << 5 ) - hash + user . id . charCodeAt ( i ) ;
1754+ hash = hash & hash ;
1755+ }
1756+ const totalCount =
1757+ ( ctx as Context & { previewTotalCount ?: number } )
1758+ . previewTotalCount || 1000 ;
1759+ const anonNumber = ( Math . abs ( hash ) % totalCount ) + 1 ;
1760+ return `anon #${ anonNumber } ` ;
1761+ } ,
1762+ } ,
1763+ description : {
1764+ select : ( ) => 'NULL' ,
1765+ transform : async ( _ , ctx , parent ) => {
1766+ const user = parent as User ;
1767+ try {
1768+ const profile = await snotraClient . getProfile ( {
1769+ user_id : user . id ,
1770+ } ) ;
1771+ return profile ?. profile_text || null ;
1772+ } catch ( error ) {
1773+ return null ;
1774+ }
1775+ } ,
1776+ } ,
1777+ openToWork : {
1778+ select : ( _ , alias , qb ) =>
1779+ qb
1780+ . select ( 'ucp.status' )
1781+ . from ( 'user_candidate_preference' , 'ucp' )
1782+ . where ( `ucp."userId" = ${ alias } .id` )
1783+ . limit ( 1 ) ,
1784+ transform : ( status : number | null ) : boolean => status === 1 ,
1785+ } ,
1786+ seniority : {
1787+ select : 'experienceLevel' ,
1788+ } ,
1789+ company : {
1790+ relation : {
1791+ isMany : false ,
1792+ customRelation : ( _ , parentAlias , childAlias , qb ) : QueryBuilder =>
1793+ qb
1794+ . where ( `${ childAlias } ."userId" = ${ parentAlias } .id` )
1795+ . andWhere ( `${ childAlias } .verified = true` )
1796+ . andWhere ( `${ childAlias } .type = '1'` )
1797+ . orderBy ( `${ childAlias } ."startedAt"` , 'DESC' )
1798+ . limit ( 1 ) ,
1799+ } ,
1800+ } ,
1801+ location : {
1802+ select : ( _ , alias ) => `
1803+ COALESCE(
1804+ (
1805+ SELECT jsonb_build_object(
1806+ 'city', location->0->>'city',
1807+ 'subdivision', location->0->>'subdivision',
1808+ 'country', location->0->>'country'
1809+ )
1810+ FROM user_candidate_preference
1811+ WHERE "userId" = ${ alias } .id
1812+ LIMIT 1
1813+ ),
1814+ ${ alias } .flags
1815+ )
1816+ ` ,
1817+ transform : ( data : Record < string , unknown > ) : string | null => {
1818+ if ( ! data ) return null ;
1819+
1820+ if ( data . city || data . subdivision || data . country ) {
1821+ return [ data . city , data . subdivision , data . country ]
1822+ . filter ( Boolean )
1823+ . join ( ', ' ) ;
1824+ }
1825+
1826+ return null ;
1827+ } ,
1828+ } ,
1829+
1830+ lastActivity : {
1831+ select : ( ) => 'NULL' ,
1832+ transform : async ( _ , ctx , parent ) => {
1833+ const user = parent as User ;
1834+ if ( ! user . id ) {
1835+ return null ;
1836+ }
1837+ return await ctx . dataLoader . userLastActive . load ( {
1838+ userId : user . id ,
1839+ } ) ;
1840+ } ,
1841+ } ,
1842+ topTags : {
1843+ select : ( ) => 'NULL' ,
1844+ transform : async ( _ , ctx , parent ) => {
1845+ const user = parent as User ;
1846+ if ( ! user . id ) {
1847+ return null ;
1848+ }
1849+ try {
1850+ const tags = await getUserTopReadingTags ( ctx . con , {
1851+ userId : user . id ,
1852+ limit : 5 ,
1853+ readLimit : 100 ,
1854+ } ) ;
1855+ return tags && tags . length > 0 ? tags . map ( ( t ) => t . tag ) : null ;
1856+ } catch ( error ) {
1857+ return null ;
1858+ }
1859+ } ,
1860+ } ,
1861+ recentlyRead : {
1862+ select : ( _ , alias , qb ) =>
1863+ qb . select ( `
1864+ ARRAY(
1865+ SELECT jsonb_build_object(
1866+ 'tag', utr."keywordValue",
1867+ 'issuedAt', utr."issuedAt"
1868+ )
1869+ FROM user_top_reader utr
1870+ WHERE utr."userId" = ${ alias } .id
1871+ ORDER BY utr."issuedAt" DESC
1872+ LIMIT 3
1873+ )
1874+ ` ) ,
1875+ transform : (
1876+ badges : Array < { tag : string ; issuedAt : string } > | null ,
1877+ ) : Array < { tag : string ; issuedAt : string } > | null => {
1878+ return badges && badges . length > 0 ? badges : null ;
1879+ } ,
1880+ } ,
1881+ activeSquads : {
1882+ select : ( _ , alias ) => `
1883+ ARRAY(
1884+ SELECT sm."sourceId"
1885+ FROM source_member sm
1886+ INNER JOIN source s ON s.id = sm."sourceId"
1887+ WHERE sm."userId" = ${ alias } .id
1888+ AND s.type = '${ SourceType . Squad } '
1889+ AND s.active = true
1890+ ORDER BY sm."createdAt" DESC
1891+ LIMIT 5
1892+ )
1893+ ` ,
1894+ } ,
1895+ } ,
1896+ } ,
17181897} ) ;
17191898
17201899export default obj ;
0 commit comments